blob: 381d467cf55b80bc45963167cdd2c14105e16bea [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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-10-28 22:53:37 +100031#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/processor.h>
33#include <asm/pgtable.h>
34#include <asm/mmu.h>
35#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/cputable.h>
37#include <asm/rtas.h>
38#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100039#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020040#include <asm/spu.h>
41#include <asm/spu_priv1.h>
Stephen Rothwell1d135812006-11-13 14:50:28 +110042#include <asm/firmware.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100043
44#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100046#include <asm/paca.h>
Stephen Rothwellbbb68172006-11-30 11:44:09 +110047#include <asm/iseries/it_lp_reg_save.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100048#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010051#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#define scanhex xmon_scanhex
54#define skipbl xmon_skipbl
55
56#ifdef CONFIG_SMP
57cpumask_t cpus_in_xmon = CPU_MASK_NONE;
58static unsigned long xmon_taken = 1;
59static int xmon_owner;
60static int xmon_gate;
61#endif /* CONFIG_SMP */
62
63static unsigned long in_xmon = 0;
64
65static unsigned long adrs;
66static int size = 1;
67#define MAX_DUMP (128 * 1024)
68static unsigned long ndump = 64;
69static unsigned long nidump = 16;
70static unsigned long ncsum = 4096;
71static int termch;
72static char tmpstr[128];
73
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100074#define JMP_BUF_LEN 23
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];
78#define setjmp xmon_setjmp
79#define longjmp xmon_longjmp
80
81/* Breakpoint stuff */
82struct bpt {
83 unsigned long address;
84 unsigned int instr[2];
85 atomic_t ref_count;
86 int enabled;
87 unsigned long pad;
88};
89
90/* Bits in bpt.enabled */
91#define BP_IABR_TE 1 /* IABR translation enabled */
92#define BP_IABR 2
93#define BP_TRAP 8
94#define BP_DABR 0x10
95
96#define NBPTS 256
97static struct bpt bpts[NBPTS];
98static struct bpt dabr;
99static struct bpt *iabr;
100static unsigned bpinstr = 0x7fe00008; /* trap */
101
102#define BP_NUM(bp) ((bp) - bpts + 1)
103
104/* Prototypes */
105static int cmds(struct pt_regs *);
106static int mread(unsigned long, void *, int);
107static int mwrite(unsigned long, void *, int);
108static int handle_fault(struct pt_regs *);
109static void byterev(unsigned char *, int);
110static void memex(void);
111static int bsesc(void);
112static void dump(void);
113static void prdump(unsigned long, long);
114static int ppc_inst_dump(unsigned long, long, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115static void backtrace(struct pt_regs *);
116static void excprint(struct pt_regs *);
117static void prregs(struct pt_regs *);
118static void memops(int);
119static void memlocate(void);
120static void memzcan(void);
121static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
122int skipbl(void);
123int scanhex(unsigned long *valp);
124static void scannl(void);
125static int hexdigit(int);
126void getstring(char *, int);
127static void flush_input(void);
128static int inchar(void);
129static void take_input(char *);
130static unsigned long read_spr(int);
131static void write_spr(int, unsigned long);
132static void super_regs(void);
133static void remove_bpts(void);
134static void insert_bpts(void);
135static void remove_cpu_bpts(void);
136static void insert_cpu_bpts(void);
137static struct bpt *at_breakpoint(unsigned long pc);
138static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
139static int do_step(struct pt_regs *);
140static void bpt_cmds(void);
141static void cacheflush(void);
142static int cpu_cmd(void);
143static void csum(void);
144static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000145static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146void dump_segments(void);
147static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200148static void xmon_show_stack(unsigned long sp, unsigned long lr,
149 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static void xmon_print_symbol(unsigned long address, const char *mid,
151 const char *after);
152static const char *getvecname(unsigned long vec);
153
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200154static int do_spu_cmd(void);
155
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100156#ifdef CONFIG_44x
157static void dump_tlb_44x(void);
158#endif
159
Olaf Hering26c8af52006-09-08 16:29:21 +0200160int xmon_no_auto_backtrace;
161
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000162extern void xmon_enter(void);
163extern void xmon_leave(void);
164
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000165extern long setjmp(long *);
166extern void longjmp(long *, long);
167extern void xmon_save_regs(struct pt_regs *);
168
169#ifdef CONFIG_PPC64
170#define REG "%.16lx"
171#define REGS_PER_LINE 4
172#define LAST_VOLATILE 13
173#else
174#define REG "%.8lx"
175#define REGS_PER_LINE 8
176#define LAST_VOLATILE 12
177#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
180
181#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
182 || ('a' <= (c) && (c) <= 'f') \
183 || ('A' <= (c) && (c) <= 'F'))
184#define isalnum(c) (('0' <= (c) && (c) <= '9') \
185 || ('a' <= (c) && (c) <= 'z') \
186 || ('A' <= (c) && (c) <= 'Z'))
187#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
188
189static char *help_string = "\
190Commands:\n\
191 b show breakpoints\n\
192 bd set data breakpoint\n\
193 bi set instruction breakpoint\n\
194 bc clear breakpoint\n"
195#ifdef CONFIG_SMP
196 "\
197 c print cpus stopped in xmon\n\
198 c# try to switch to cpu number h (in hex)\n"
199#endif
200 "\
201 C checksum\n\
202 d dump bytes\n\
203 di dump instructions\n\
204 df dump float values\n\
205 dd dump double values\n\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100206 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 e print exception information\n\
208 f flush cache\n\
209 la lookup symbol+offset of specified address\n\
210 ls lookup address of specified symbol\n\
211 m examine/change memory\n\
212 mm move a block of memory\n\
213 ms set a block of memory\n\
214 md compare two blocks of memory\n\
215 ml locate a block of memory\n\
216 mz zero a block of memory\n\
217 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000218 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200220 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100221#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200222" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200223 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100224 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900225 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100226 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200227#endif
228" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000231 X exit monitor and dont recover\n"
232#ifdef CONFIG_PPC64
233" u dump segment table or SLB\n"
234#endif
235#ifdef CONFIG_PPC_STD_MMU_32
236" u dump segment registers\n"
237#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100238#ifdef CONFIG_44x
239" u dump TLB\n"
240#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000241" ? help\n"
242" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 zh halt\n"
244;
245
246static struct pt_regs *xmon_regs;
247
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000248static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
250 asm volatile("sync; isync");
251}
252
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000253static inline void store_inst(void *p)
254{
255 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
256}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000258static inline void cflush(void *p)
259{
260 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
261}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000263static inline void cinval(void *p)
264{
265 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
266}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268/*
269 * Disable surveillance (the service processor watchdog function)
270 * while we are in xmon.
271 * XXX we should re-enable it when we leave. :)
272 */
273#define SURVEILLANCE_TOKEN 9000
274
275static inline void disable_surveillance(void)
276{
277#ifdef CONFIG_PPC_PSERIES
278 /* Since this can't be a module, args should end up below 4GB. */
279 static struct rtas_args args;
280
281 /*
282 * At this point we have got all the cpus we can into
283 * xmon, so there is hopefully no other cpu calling RTAS
284 * at the moment, even though we don't take rtas.lock.
285 * If we did try to take rtas.lock there would be a
286 * real possibility of deadlock.
287 */
288 args.token = rtas_token("set-indicator");
289 if (args.token == RTAS_UNKNOWN_SERVICE)
290 return;
291 args.nargs = 3;
292 args.nret = 1;
293 args.rets = &args.args[3];
294 args.args[0] = SURVEILLANCE_TOKEN;
295 args.args[1] = 0;
296 args.args[2] = 0;
297 enter_rtas(__pa(&args));
298#endif /* CONFIG_PPC_PSERIES */
299}
300
301#ifdef CONFIG_SMP
302static int xmon_speaker;
303
304static void get_output_lock(void)
305{
306 int me = smp_processor_id() + 0x100;
307 int last_speaker = 0, prev;
308 long timeout;
309
310 if (xmon_speaker == me)
311 return;
312 for (;;) {
313 if (xmon_speaker == 0) {
314 last_speaker = cmpxchg(&xmon_speaker, 0, me);
315 if (last_speaker == 0)
316 return;
317 }
318 timeout = 10000000;
319 while (xmon_speaker == last_speaker) {
320 if (--timeout > 0)
321 continue;
322 /* hostile takeover */
323 prev = cmpxchg(&xmon_speaker, last_speaker, me);
324 if (prev == last_speaker)
325 return;
326 break;
327 }
328 }
329}
330
331static void release_output_lock(void)
332{
333 xmon_speaker = 0;
334}
335#endif
336
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000337static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 struct bpt *bp;
341 long recurse_jmp[JMP_BUF_LEN];
342 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100343 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344#ifdef CONFIG_SMP
345 int cpu;
346 int secondary;
347 unsigned long timeout;
348#endif
349
Anton Blanchardf13659e2007-03-21 01:48:34 +1100350 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352 bp = in_breakpoint_table(regs->nip, &offset);
353 if (bp != NULL) {
354 regs->nip = bp->address + offset;
355 atomic_dec(&bp->ref_count);
356 }
357
358 remove_cpu_bpts();
359
360#ifdef CONFIG_SMP
361 cpu = smp_processor_id();
362 if (cpu_isset(cpu, cpus_in_xmon)) {
363 get_output_lock();
364 excprint(regs);
365 printf("cpu 0x%x: Exception %lx %s in xmon, "
366 "returning to main loop\n",
367 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000368 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 longjmp(xmon_fault_jmp[cpu], 1);
370 }
371
372 if (setjmp(recurse_jmp) != 0) {
373 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000374 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 printf("xmon: WARNING: bad recursive fault "
376 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000377 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 goto waiting;
379 }
380 secondary = !(xmon_taken && cpu == xmon_owner);
381 goto cmdloop;
382 }
383
384 xmon_fault_jmp[cpu] = recurse_jmp;
385 cpu_set(cpu, cpus_in_xmon);
386
387 bp = NULL;
388 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
389 bp = at_breakpoint(regs->nip);
390 if (bp || (regs->msr & MSR_RI) == 0)
391 fromipi = 0;
392
393 if (!fromipi) {
394 get_output_lock();
395 excprint(regs);
396 if (bp) {
397 printf("cpu 0x%x stopped at breakpoint 0x%x (",
398 cpu, BP_NUM(bp));
399 xmon_print_symbol(regs->nip, " ", ")\n");
400 }
401 if ((regs->msr & MSR_RI) == 0)
402 printf("WARNING: exception is not recoverable, "
403 "can't continue\n");
404 release_output_lock();
405 }
406
407 waiting:
408 secondary = 1;
409 while (secondary && !xmon_gate) {
410 if (in_xmon == 0) {
411 if (fromipi)
412 goto leave;
413 secondary = test_and_set_bit(0, &in_xmon);
414 }
415 barrier();
416 }
417
418 if (!secondary && !xmon_gate) {
419 /* we are the first cpu to come in */
420 /* interrupt other cpu(s) */
421 int ncpus = num_online_cpus();
422
423 xmon_owner = cpu;
424 mb();
425 if (ncpus > 1) {
426 smp_send_debugger_break(MSG_ALL_BUT_SELF);
427 /* wait for other cpus to come in */
428 for (timeout = 100000000; timeout != 0; --timeout) {
429 if (cpus_weight(cpus_in_xmon) >= ncpus)
430 break;
431 barrier();
432 }
433 }
434 remove_bpts();
435 disable_surveillance();
436 /* for breakpoint or single step, print the current instr. */
437 if (bp || TRAP(regs) == 0xd00)
438 ppc_inst_dump(regs->nip, 1, 0);
439 printf("enter ? for help\n");
440 mb();
441 xmon_gate = 1;
442 barrier();
443 }
444
445 cmdloop:
446 while (in_xmon) {
447 if (secondary) {
448 if (cpu == xmon_owner) {
449 if (!test_and_set_bit(0, &xmon_taken)) {
450 secondary = 0;
451 continue;
452 }
453 /* missed it */
454 while (cpu == xmon_owner)
455 barrier();
456 }
457 barrier();
458 } else {
459 cmd = cmds(regs);
460 if (cmd != 0) {
461 /* exiting xmon */
462 insert_bpts();
463 xmon_gate = 0;
464 wmb();
465 in_xmon = 0;
466 break;
467 }
468 /* have switched to some other cpu */
469 secondary = 1;
470 }
471 }
472 leave:
473 cpu_clear(cpu, cpus_in_xmon);
474 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475#else
476 /* UP is simple... */
477 if (in_xmon) {
478 printf("Exception %lx %s in xmon, returning to main loop\n",
479 regs->trap, getvecname(TRAP(regs)));
480 longjmp(xmon_fault_jmp[0], 1);
481 }
482 if (setjmp(recurse_jmp) == 0) {
483 xmon_fault_jmp[0] = recurse_jmp;
484 in_xmon = 1;
485
486 excprint(regs);
487 bp = at_breakpoint(regs->nip);
488 if (bp) {
489 printf("Stopped at breakpoint %x (", BP_NUM(bp));
490 xmon_print_symbol(regs->nip, " ", ")\n");
491 }
492 if ((regs->msr & MSR_RI) == 0)
493 printf("WARNING: exception is not recoverable, "
494 "can't continue\n");
495 remove_bpts();
496 disable_surveillance();
497 /* for breakpoint or single step, print the current instr. */
498 if (bp || TRAP(regs) == 0xd00)
499 ppc_inst_dump(regs->nip, 1, 0);
500 printf("enter ? for help\n");
501 }
502
503 cmd = cmds(regs);
504
505 insert_bpts();
506 in_xmon = 0;
507#endif
508
509 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
510 bp = at_breakpoint(regs->nip);
511 if (bp != NULL) {
512 int stepped = emulate_step(regs, bp->instr[0]);
513 if (stepped == 0) {
514 regs->nip = (unsigned long) &bp->instr[0];
515 atomic_inc(&bp->ref_count);
516 } else if (stepped < 0) {
517 printf("Couldn't single-step %s instruction\n",
518 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
519 }
520 }
521 }
522
523 insert_cpu_bpts();
524
Anton Blanchardf13659e2007-03-21 01:48:34 +1100525 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000527 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528}
529
530int xmon(struct pt_regs *excp)
531{
532 struct pt_regs regs;
533
534 if (excp == NULL) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000535 xmon_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 excp = &regs;
537 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 return xmon_core(excp, 0);
540}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000541EXPORT_SYMBOL(xmon);
542
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000543irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000544{
545 unsigned long flags;
546 local_irq_save(flags);
547 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000548 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000549 local_irq_restore(flags);
550 return IRQ_HANDLED;
551}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000553static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
555 struct bpt *bp;
556 unsigned long offset;
557
558 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
559 return 0;
560
561 /* Are we at the trap at bp->instr[1] for some bp? */
562 bp = in_breakpoint_table(regs->nip, &offset);
563 if (bp != NULL && offset == 4) {
564 regs->nip = bp->address + 4;
565 atomic_dec(&bp->ref_count);
566 return 1;
567 }
568
569 /* Are we at a breakpoint? */
570 bp = at_breakpoint(regs->nip);
571 if (!bp)
572 return 0;
573
574 xmon_core(regs, 0);
575
576 return 1;
577}
578
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000579static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
581 if (user_mode(regs))
582 return 0;
583 xmon_core(regs, 0);
584 return 1;
585}
586
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000587static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
589 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
590 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000591 if (dabr.enabled == 0)
592 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 xmon_core(regs, 0);
594 return 1;
595}
596
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000597static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598{
599 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
600 return 0;
601 if (iabr == 0)
602 return 0;
603 xmon_core(regs, 0);
604 return 1;
605}
606
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000607static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609#ifdef CONFIG_SMP
610 if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
611 xmon_core(regs, 1);
612#endif
613 return 0;
614}
615
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000616static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
618 struct bpt *bp;
619 unsigned long offset;
620
621 if (in_xmon && catch_memory_errors)
622 handle_fault(regs); /* doesn't return */
623
624 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
625 bp = in_breakpoint_table(regs->nip, &offset);
626 if (bp != NULL) {
627 regs->nip = bp->address + offset;
628 atomic_dec(&bp->ref_count);
629 }
630 }
631
632 return 0;
633}
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635static struct bpt *at_breakpoint(unsigned long pc)
636{
637 int i;
638 struct bpt *bp;
639
640 bp = bpts;
641 for (i = 0; i < NBPTS; ++i, ++bp)
642 if (bp->enabled && pc == bp->address)
643 return bp;
644 return NULL;
645}
646
647static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
648{
649 unsigned long off;
650
651 off = nip - (unsigned long) bpts;
652 if (off >= sizeof(bpts))
653 return NULL;
654 off %= sizeof(struct bpt);
655 if (off != offsetof(struct bpt, instr[0])
656 && off != offsetof(struct bpt, instr[1]))
657 return NULL;
658 *offp = off - offsetof(struct bpt, instr[0]);
659 return (struct bpt *) (nip - off);
660}
661
662static struct bpt *new_breakpoint(unsigned long a)
663{
664 struct bpt *bp;
665
666 a &= ~3UL;
667 bp = at_breakpoint(a);
668 if (bp)
669 return bp;
670
671 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
672 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
673 bp->address = a;
674 bp->instr[1] = bpinstr;
675 store_inst(&bp->instr[1]);
676 return bp;
677 }
678 }
679
680 printf("Sorry, no free breakpoints. Please clear one first.\n");
681 return NULL;
682}
683
684static void insert_bpts(void)
685{
686 int i;
687 struct bpt *bp;
688
689 bp = bpts;
690 for (i = 0; i < NBPTS; ++i, ++bp) {
691 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
692 continue;
693 if (mread(bp->address, &bp->instr[0], 4) != 4) {
694 printf("Couldn't read instruction at %lx, "
695 "disabling breakpoint there\n", bp->address);
696 bp->enabled = 0;
697 continue;
698 }
699 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
700 printf("Breakpoint at %lx is on an mtmsrd or rfid "
701 "instruction, disabling it\n", bp->address);
702 bp->enabled = 0;
703 continue;
704 }
705 store_inst(&bp->instr[0]);
706 if (bp->enabled & BP_IABR)
707 continue;
708 if (mwrite(bp->address, &bpinstr, 4) != 4) {
709 printf("Couldn't write instruction at %lx, "
710 "disabling breakpoint there\n", bp->address);
711 bp->enabled &= ~BP_TRAP;
712 continue;
713 }
714 store_inst((void *)bp->address);
715 }
716}
717
718static void insert_cpu_bpts(void)
719{
720 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000721 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000723 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
725}
726
727static void remove_bpts(void)
728{
729 int i;
730 struct bpt *bp;
731 unsigned instr;
732
733 bp = bpts;
734 for (i = 0; i < NBPTS; ++i, ++bp) {
735 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
736 continue;
737 if (mread(bp->address, &instr, 4) == 4
738 && instr == bpinstr
739 && mwrite(bp->address, &bp->instr, 4) != 4)
740 printf("Couldn't remove breakpoint at %lx\n",
741 bp->address);
742 else
743 store_inst((void *)bp->address);
744 }
745}
746
747static void remove_cpu_bpts(void)
748{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000749 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000751 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
754/* Command interpreting routine */
755static char *last_cmd;
756
757static int
758cmds(struct pt_regs *excp)
759{
760 int cmd = 0;
761
762 last_cmd = NULL;
763 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200764
765 if (!xmon_no_auto_backtrace) {
766 xmon_no_auto_backtrace = 1;
767 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
768 }
769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 for(;;) {
771#ifdef CONFIG_SMP
772 printf("%x:", smp_processor_id());
773#endif /* CONFIG_SMP */
774 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 flush_input();
776 termch = 0;
777 cmd = skipbl();
778 if( cmd == '\n' ) {
779 if (last_cmd == NULL)
780 continue;
781 take_input(last_cmd);
782 last_cmd = NULL;
783 cmd = inchar();
784 }
785 switch (cmd) {
786 case 'm':
787 cmd = inchar();
788 switch (cmd) {
789 case 'm':
790 case 's':
791 case 'd':
792 memops(cmd);
793 break;
794 case 'l':
795 memlocate();
796 break;
797 case 'z':
798 memzcan();
799 break;
800 case 'i':
801 show_mem();
802 break;
803 default:
804 termch = cmd;
805 memex();
806 }
807 break;
808 case 'd':
809 dump();
810 break;
811 case 'l':
812 symbol_lookup();
813 break;
814 case 'r':
815 prregs(excp); /* print regs */
816 break;
817 case 'e':
818 excprint(excp);
819 break;
820 case 'S':
821 super_regs();
822 break;
823 case 't':
824 backtrace(excp);
825 break;
826 case 'f':
827 cacheflush();
828 break;
829 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200830 if (do_spu_cmd() == 0)
831 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if (do_step(excp))
833 return cmd;
834 break;
835 case 'x':
836 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100837 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100839 printf(" <no input ...>\n");
840 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 return cmd;
842 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000843 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 case 'b':
846 bpt_cmds();
847 break;
848 case 'C':
849 csum();
850 break;
851 case 'c':
852 if (cpu_cmd())
853 return 0;
854 break;
855 case 'z':
856 bootcmds();
857 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000858 case 'p':
859 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000861#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 case 'u':
863 dump_segments();
864 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000865#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100866#ifdef CONFIG_4xx
867 case 'u':
868 dump_tlb_44x();
869 break;
870#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 default:
872 printf("Unrecognized command: ");
873 do {
874 if (' ' < cmd && cmd <= '~')
875 putchar(cmd);
876 else
877 printf("\\x%x", cmd);
878 cmd = inchar();
879 } while (cmd != '\n');
880 printf(" (type ? for help)\n");
881 break;
882 }
883 }
884}
885
886/*
887 * Step a single instruction.
888 * Some instructions we emulate, others we execute with MSR_SE set.
889 */
890static int do_step(struct pt_regs *regs)
891{
892 unsigned int instr;
893 int stepped;
894
895 /* check we are in 64-bit kernel mode, translation enabled */
896 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
897 if (mread(regs->nip, &instr, 4) == 4) {
898 stepped = emulate_step(regs, instr);
899 if (stepped < 0) {
900 printf("Couldn't single-step %s instruction\n",
901 (IS_RFID(instr)? "rfid": "mtmsrd"));
902 return 0;
903 }
904 if (stepped > 0) {
905 regs->trap = 0xd00 | (regs->trap & 1);
906 printf("stepped to ");
907 xmon_print_symbol(regs->nip, " ", "\n");
908 ppc_inst_dump(regs->nip, 1, 0);
909 return 0;
910 }
911 }
912 }
913 regs->msr |= MSR_SE;
914 return 1;
915}
916
917static void bootcmds(void)
918{
919 int cmd;
920
921 cmd = inchar();
922 if (cmd == 'r')
923 ppc_md.restart(NULL);
924 else if (cmd == 'h')
925 ppc_md.halt();
926 else if (cmd == 'p')
927 ppc_md.power_off();
928}
929
930static int cpu_cmd(void)
931{
932#ifdef CONFIG_SMP
933 unsigned long cpu;
934 int timeout;
935 int count;
936
937 if (!scanhex(&cpu)) {
938 /* print cpus waiting or in xmon */
939 printf("cpus stopped:");
940 count = 0;
941 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
942 if (cpu_isset(cpu, cpus_in_xmon)) {
943 if (count == 0)
944 printf(" %x", cpu);
945 ++count;
946 } else {
947 if (count > 1)
948 printf("-%x", cpu - 1);
949 count = 0;
950 }
951 }
952 if (count > 1)
953 printf("-%x", NR_CPUS - 1);
954 printf("\n");
955 return 0;
956 }
957 /* try to switch to cpu specified */
958 if (!cpu_isset(cpu, cpus_in_xmon)) {
959 printf("cpu 0x%x isn't in xmon\n", cpu);
960 return 0;
961 }
962 xmon_taken = 0;
963 mb();
964 xmon_owner = cpu;
965 timeout = 10000000;
966 while (!xmon_taken) {
967 if (--timeout == 0) {
968 if (test_and_set_bit(0, &xmon_taken))
969 break;
970 /* take control back */
971 mb();
972 xmon_owner = smp_processor_id();
973 printf("cpu %u didn't take control\n", cpu);
974 return 0;
975 }
976 barrier();
977 }
978 return 1;
979#else
980 return 0;
981#endif /* CONFIG_SMP */
982}
983
984static unsigned short fcstab[256] = {
985 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
986 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
987 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
988 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
989 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
990 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
991 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
992 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
993 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
994 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
995 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
996 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
997 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
998 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
999 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1000 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1001 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1002 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1003 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1004 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1005 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1006 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1007 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1008 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1009 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1010 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1011 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1012 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1013 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1014 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1015 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1016 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1017};
1018
1019#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1020
1021static void
1022csum(void)
1023{
1024 unsigned int i;
1025 unsigned short fcs;
1026 unsigned char v;
1027
1028 if (!scanhex(&adrs))
1029 return;
1030 if (!scanhex(&ncsum))
1031 return;
1032 fcs = 0xffff;
1033 for (i = 0; i < ncsum; ++i) {
1034 if (mread(adrs+i, &v, 1) == 0) {
1035 printf("csum stopped at %x\n", adrs+i);
1036 break;
1037 }
1038 fcs = FCS(fcs, v);
1039 }
1040 printf("%x\n", fcs);
1041}
1042
1043/*
1044 * Check if this is a suitable place to put a breakpoint.
1045 */
1046static long check_bp_loc(unsigned long addr)
1047{
1048 unsigned int instr;
1049
1050 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001051 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 printf("Breakpoints may only be placed at kernel addresses\n");
1053 return 0;
1054 }
1055 if (!mread(addr, &instr, sizeof(instr))) {
1056 printf("Can't read instruction at address %lx\n", addr);
1057 return 0;
1058 }
1059 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1060 printf("Breakpoints may not be placed on mtmsrd or rfid "
1061 "instructions\n");
1062 return 0;
1063 }
1064 return 1;
1065}
1066
1067static char *breakpoint_help_string =
1068 "Breakpoint command usage:\n"
1069 "b show breakpoints\n"
1070 "b <addr> [cnt] set breakpoint at given instr addr\n"
1071 "bc clear all breakpoints\n"
1072 "bc <n/addr> clear breakpoint number n or at addr\n"
1073 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1074 "bd <addr> [cnt] set hardware data breakpoint\n"
1075 "";
1076
1077static void
1078bpt_cmds(void)
1079{
1080 int cmd;
1081 unsigned long a;
1082 int mode, i;
1083 struct bpt *bp;
1084 const char badaddr[] = "Only kernel addresses are permitted "
1085 "for breakpoints\n";
1086
1087 cmd = inchar();
1088 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001089#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 case 'd': /* bd - hardware data breakpoint */
1091 mode = 7;
1092 cmd = inchar();
1093 if (cmd == 'r')
1094 mode = 5;
1095 else if (cmd == 'w')
1096 mode = 6;
1097 else
1098 termch = cmd;
1099 dabr.address = 0;
1100 dabr.enabled = 0;
1101 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001102 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 printf(badaddr);
1104 break;
1105 }
1106 dabr.address &= ~7;
1107 dabr.enabled = mode | BP_DABR;
1108 }
1109 break;
1110
1111 case 'i': /* bi - hardware instr breakpoint */
1112 if (!cpu_has_feature(CPU_FTR_IABR)) {
1113 printf("Hardware instruction breakpoint "
1114 "not supported on this cpu\n");
1115 break;
1116 }
1117 if (iabr) {
1118 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1119 iabr = NULL;
1120 }
1121 if (!scanhex(&a))
1122 break;
1123 if (!check_bp_loc(a))
1124 break;
1125 bp = new_breakpoint(a);
1126 if (bp != NULL) {
1127 bp->enabled |= BP_IABR | BP_IABR_TE;
1128 iabr = bp;
1129 }
1130 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001131#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 case 'c':
1134 if (!scanhex(&a)) {
1135 /* clear all breakpoints */
1136 for (i = 0; i < NBPTS; ++i)
1137 bpts[i].enabled = 0;
1138 iabr = NULL;
1139 dabr.enabled = 0;
1140 printf("All breakpoints cleared\n");
1141 break;
1142 }
1143
1144 if (a <= NBPTS && a >= 1) {
1145 /* assume a breakpoint number */
1146 bp = &bpts[a-1]; /* bp nums are 1 based */
1147 } else {
1148 /* assume a breakpoint address */
1149 bp = at_breakpoint(a);
1150 if (bp == 0) {
1151 printf("No breakpoint at %x\n", a);
1152 break;
1153 }
1154 }
1155
1156 printf("Cleared breakpoint %x (", BP_NUM(bp));
1157 xmon_print_symbol(bp->address, " ", ")\n");
1158 bp->enabled = 0;
1159 break;
1160
1161 default:
1162 termch = cmd;
1163 cmd = skipbl();
1164 if (cmd == '?') {
1165 printf(breakpoint_help_string);
1166 break;
1167 }
1168 termch = cmd;
1169 if (!scanhex(&a)) {
1170 /* print all breakpoints */
1171 printf(" type address\n");
1172 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001173 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 if (dabr.enabled & 1)
1175 printf("r");
1176 if (dabr.enabled & 2)
1177 printf("w");
1178 printf("]\n");
1179 }
1180 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1181 if (!bp->enabled)
1182 continue;
1183 printf("%2x %s ", BP_NUM(bp),
1184 (bp->enabled & BP_IABR)? "inst": "trap");
1185 xmon_print_symbol(bp->address, " ", "\n");
1186 }
1187 break;
1188 }
1189
1190 if (!check_bp_loc(a))
1191 break;
1192 bp = new_breakpoint(a);
1193 if (bp != NULL)
1194 bp->enabled |= BP_TRAP;
1195 break;
1196 }
1197}
1198
1199/* Very cheap human name for vector lookup. */
1200static
1201const char *getvecname(unsigned long vec)
1202{
1203 char *ret;
1204
1205 switch (vec) {
1206 case 0x100: ret = "(System Reset)"; break;
1207 case 0x200: ret = "(Machine Check)"; break;
1208 case 0x300: ret = "(Data Access)"; break;
1209 case 0x380: ret = "(Data SLB Access)"; break;
1210 case 0x400: ret = "(Instruction Access)"; break;
1211 case 0x480: ret = "(Instruction SLB Access)"; break;
1212 case 0x500: ret = "(Hardware Interrupt)"; break;
1213 case 0x600: ret = "(Alignment)"; break;
1214 case 0x700: ret = "(Program Check)"; break;
1215 case 0x800: ret = "(FPU Unavailable)"; break;
1216 case 0x900: ret = "(Decrementer)"; break;
1217 case 0xc00: ret = "(System Call)"; break;
1218 case 0xd00: ret = "(Single Step)"; break;
1219 case 0xf00: ret = "(Performance Monitor)"; break;
1220 case 0xf20: ret = "(Altivec Unavailable)"; break;
1221 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1222 default: ret = "";
1223 }
1224 return ret;
1225}
1226
1227static void get_function_bounds(unsigned long pc, unsigned long *startp,
1228 unsigned long *endp)
1229{
1230 unsigned long size, offset;
1231 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 *startp = *endp = 0;
1234 if (pc == 0)
1235 return;
1236 if (setjmp(bus_error_jmp) == 0) {
1237 catch_memory_errors = 1;
1238 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001239 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 if (name != NULL) {
1241 *startp = pc - offset;
1242 *endp = pc - offset + size;
1243 }
1244 sync();
1245 }
1246 catch_memory_errors = 0;
1247}
1248
1249static int xmon_depth_to_print = 64;
1250
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001251#ifdef CONFIG_PPC64
1252#define LRSAVE_OFFSET 0x10
1253#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1254#define MARKER_OFFSET 0x60
1255#define REGS_OFFSET 0x70
1256#else
1257#define LRSAVE_OFFSET 4
1258#define REG_FRAME_MARKER 0x72656773
1259#define MARKER_OFFSET 8
1260#define REGS_OFFSET 16
1261#endif
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263static void xmon_show_stack(unsigned long sp, unsigned long lr,
1264 unsigned long pc)
1265{
1266 unsigned long ip;
1267 unsigned long newsp;
1268 unsigned long marker;
1269 int count = 0;
1270 struct pt_regs regs;
1271
1272 do {
1273 if (sp < PAGE_OFFSET) {
1274 if (sp != 0)
1275 printf("SP (%lx) is in userspace\n", sp);
1276 break;
1277 }
1278
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001279 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 || !mread(sp, &newsp, sizeof(unsigned long))) {
1281 printf("Couldn't read stack frame at %lx\n", sp);
1282 break;
1283 }
1284
1285 /*
1286 * For the first stack frame, try to work out if
1287 * LR and/or the saved LR value in the bottommost
1288 * stack frame are valid.
1289 */
1290 if ((pc | lr) != 0) {
1291 unsigned long fnstart, fnend;
1292 unsigned long nextip;
1293 int printip = 1;
1294
1295 get_function_bounds(pc, &fnstart, &fnend);
1296 nextip = 0;
1297 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001298 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 sizeof(unsigned long));
1300 if (lr == ip) {
1301 if (lr < PAGE_OFFSET
1302 || (fnstart <= lr && lr < fnend))
1303 printip = 0;
1304 } else if (lr == nextip) {
1305 printip = 0;
1306 } else if (lr >= PAGE_OFFSET
1307 && !(fnstart <= lr && lr < fnend)) {
1308 printf("[link register ] ");
1309 xmon_print_symbol(lr, " ", "\n");
1310 }
1311 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001312 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 xmon_print_symbol(ip, " ", " (unreliable)\n");
1314 }
1315 pc = lr = 0;
1316
1317 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001318 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 xmon_print_symbol(ip, " ", "\n");
1320 }
1321
1322 /* Look for "regshere" marker to see if this is
1323 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001324 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1325 && marker == REG_FRAME_MARKER) {
1326 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 != sizeof(regs)) {
1328 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001329 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 break;
1331 }
1332 printf("--- Exception: %lx %s at ", regs.trap,
1333 getvecname(TRAP(&regs)));
1334 pc = regs.nip;
1335 lr = regs.link;
1336 xmon_print_symbol(pc, " ", "\n");
1337 }
1338
1339 if (newsp == 0)
1340 break;
1341
1342 sp = newsp;
1343 } while (count++ < xmon_depth_to_print);
1344}
1345
1346static void backtrace(struct pt_regs *excp)
1347{
1348 unsigned long sp;
1349
1350 if (scanhex(&sp))
1351 xmon_show_stack(sp, 0, 0);
1352 else
1353 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1354 scannl();
1355}
1356
1357static void print_bug_trap(struct pt_regs *regs)
1358{
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001359 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 unsigned long addr;
1361
1362 if (regs->msr & MSR_PR)
1363 return; /* not in kernel */
1364 addr = regs->nip; /* address of trap instruction */
1365 if (addr < PAGE_OFFSET)
1366 return;
1367 bug = find_bug(regs->nip);
1368 if (bug == NULL)
1369 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001370 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 return;
1372
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001373#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001374 printf("kernel BUG at %s:%u!\n",
1375 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001376#else
1377 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1378#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379}
1380
1381void excprint(struct pt_regs *fp)
1382{
1383 unsigned long trap;
1384
1385#ifdef CONFIG_SMP
1386 printf("cpu 0x%x: ", smp_processor_id());
1387#endif /* CONFIG_SMP */
1388
1389 trap = TRAP(fp);
1390 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1391 printf(" pc: ");
1392 xmon_print_symbol(fp->nip, ": ", "\n");
1393
1394 printf(" lr: ", fp->link);
1395 xmon_print_symbol(fp->link, ": ", "\n");
1396
1397 printf(" sp: %lx\n", fp->gpr[1]);
1398 printf(" msr: %lx\n", fp->msr);
1399
1400 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1401 printf(" dar: %lx\n", fp->dar);
1402 if (trap != 0x380)
1403 printf(" dsisr: %lx\n", fp->dsisr);
1404 }
1405
1406 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001407#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001409#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (current) {
1411 printf(" pid = %ld, comm = %s\n",
1412 current->pid, current->comm);
1413 }
1414
1415 if (trap == 0x700)
1416 print_bug_trap(fp);
1417}
1418
1419void prregs(struct pt_regs *fp)
1420{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001421 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 unsigned long base;
1423 struct pt_regs regs;
1424
1425 if (scanhex(&base)) {
1426 if (setjmp(bus_error_jmp) == 0) {
1427 catch_memory_errors = 1;
1428 sync();
1429 regs = *(struct pt_regs *)base;
1430 sync();
1431 __delay(200);
1432 } else {
1433 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001434 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 base);
1436 return;
1437 }
1438 catch_memory_errors = 0;
1439 fp = &regs;
1440 }
1441
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001442#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 if (FULL_REGS(fp)) {
1444 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001445 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1447 } else {
1448 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001449 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1451 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001452#else
1453 for (n = 0; n < 32; ++n) {
1454 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1455 (n & 3) == 3? "\n": " ");
1456 if (n == 12 && !FULL_REGS(fp)) {
1457 printf("\n");
1458 break;
1459 }
1460 }
1461#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 printf("pc = ");
1463 xmon_print_symbol(fp->nip, " ", "\n");
1464 printf("lr = ");
1465 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001466 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1467 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001469 trap = TRAP(fp);
1470 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1471 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472}
1473
1474void cacheflush(void)
1475{
1476 int cmd;
1477 unsigned long nflush;
1478
1479 cmd = inchar();
1480 if (cmd != 'i')
1481 termch = cmd;
1482 scanhex((void *)&adrs);
1483 if (termch != '\n')
1484 termch = 0;
1485 nflush = 1;
1486 scanhex(&nflush);
1487 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1488 if (setjmp(bus_error_jmp) == 0) {
1489 catch_memory_errors = 1;
1490 sync();
1491
1492 if (cmd != 'i') {
1493 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1494 cflush((void *) adrs);
1495 } else {
1496 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1497 cinval((void *) adrs);
1498 }
1499 sync();
1500 /* wait a little while to see if we get a machine check */
1501 __delay(200);
1502 }
1503 catch_memory_errors = 0;
1504}
1505
1506unsigned long
1507read_spr(int n)
1508{
1509 unsigned int instrs[2];
1510 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001512#ifdef CONFIG_PPC64
1513 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 opd[0] = (unsigned long)instrs;
1516 opd[1] = 0;
1517 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001518 code = (unsigned long (*)(void)) opd;
1519#else
1520 code = (unsigned long (*)(void)) instrs;
1521#endif
1522
1523 /* mfspr r3,n; blr */
1524 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1525 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 store_inst(instrs);
1527 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
1529 if (setjmp(bus_error_jmp) == 0) {
1530 catch_memory_errors = 1;
1531 sync();
1532
1533 ret = code();
1534
1535 sync();
1536 /* wait a little while to see if we get a machine check */
1537 __delay(200);
1538 n = size;
1539 }
1540
1541 return ret;
1542}
1543
1544void
1545write_spr(int n, unsigned long val)
1546{
1547 unsigned int instrs[2];
1548 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001549#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 unsigned long opd[3];
1551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 opd[0] = (unsigned long)instrs;
1553 opd[1] = 0;
1554 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001555 code = (unsigned long (*)(unsigned long)) opd;
1556#else
1557 code = (unsigned long (*)(unsigned long)) instrs;
1558#endif
1559
1560 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1561 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 store_inst(instrs);
1563 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
1565 if (setjmp(bus_error_jmp) == 0) {
1566 catch_memory_errors = 1;
1567 sync();
1568
1569 code(val);
1570
1571 sync();
1572 /* wait a little while to see if we get a machine check */
1573 __delay(200);
1574 n = size;
1575 }
1576}
1577
1578static unsigned long regno;
1579extern char exc_prolog;
1580extern char dec_exc;
1581
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001582void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583{
1584 int cmd;
1585 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587 cmd = skipbl();
1588 if (cmd == '\n') {
1589 unsigned long sp, toc;
1590 asm("mr %0,1" : "=r" (sp) :);
1591 asm("mr %0,2" : "=r" (toc) :);
1592
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001593 printf("msr = "REG" sprg0= "REG"\n",
1594 mfmsr(), mfspr(SPRN_SPRG0));
1595 printf("pvr = "REG" sprg1= "REG"\n",
1596 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1597 printf("dec = "REG" sprg2= "REG"\n",
1598 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1599 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1600 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601#ifdef CONFIG_PPC_ISERIES
Stephen Rothwell1d135812006-11-13 14:50:28 +11001602 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1603 struct paca_struct *ptrPaca;
1604 struct lppaca *ptrLpPaca;
1605 struct ItLpRegSave *ptrLpRegSave;
1606
1607 /* Dump out relevant Paca data areas. */
1608 printf("Paca: \n");
1609 ptrPaca = get_paca();
1610
1611 printf(" Local Processor Control Area (LpPaca): \n");
1612 ptrLpPaca = ptrPaca->lppaca_ptr;
1613 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1614 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1615 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1616 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1617 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1618
1619 printf(" Local Processor Register Save Area (LpRegSave): \n");
1620 ptrLpRegSave = ptrPaca->reg_save_ptr;
1621 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1622 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1623 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1624 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1625 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1626 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628#endif
1629
1630 return;
1631 }
1632
1633 scanhex(&regno);
1634 switch (cmd) {
1635 case 'w':
1636 val = read_spr(regno);
1637 scanhex(&val);
1638 write_spr(regno, val);
1639 /* fall through */
1640 case 'r':
1641 printf("spr %lx = %lx\n", regno, read_spr(regno));
1642 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 }
1644 scannl();
1645}
1646
1647/*
1648 * Stuff for reading and writing memory safely
1649 */
1650int
1651mread(unsigned long adrs, void *buf, int size)
1652{
1653 volatile int n;
1654 char *p, *q;
1655
1656 n = 0;
1657 if (setjmp(bus_error_jmp) == 0) {
1658 catch_memory_errors = 1;
1659 sync();
1660 p = (char *)adrs;
1661 q = (char *)buf;
1662 switch (size) {
1663 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001664 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 break;
1666 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001667 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 break;
1669 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001670 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 break;
1672 default:
1673 for( ; n < size; ++n) {
1674 *q++ = *p++;
1675 sync();
1676 }
1677 }
1678 sync();
1679 /* wait a little while to see if we get a machine check */
1680 __delay(200);
1681 n = size;
1682 }
1683 catch_memory_errors = 0;
1684 return n;
1685}
1686
1687int
1688mwrite(unsigned long adrs, void *buf, int size)
1689{
1690 volatile int n;
1691 char *p, *q;
1692
1693 n = 0;
1694 if (setjmp(bus_error_jmp) == 0) {
1695 catch_memory_errors = 1;
1696 sync();
1697 p = (char *) adrs;
1698 q = (char *) buf;
1699 switch (size) {
1700 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001701 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 break;
1703 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001704 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 break;
1706 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001707 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 break;
1709 default:
1710 for ( ; n < size; ++n) {
1711 *p++ = *q++;
1712 sync();
1713 }
1714 }
1715 sync();
1716 /* wait a little while to see if we get a machine check */
1717 __delay(200);
1718 n = size;
1719 } else {
1720 printf("*** Error writing address %x\n", adrs + n);
1721 }
1722 catch_memory_errors = 0;
1723 return n;
1724}
1725
1726static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001727static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728static char *fault_chars[] = { "--", "**", "##" };
1729
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001730static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001732 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 switch (TRAP(regs)) {
1734 case 0x200:
1735 fault_type = 0;
1736 break;
1737 case 0x300:
1738 case 0x380:
1739 fault_type = 1;
1740 break;
1741 default:
1742 fault_type = 2;
1743 }
1744
1745 longjmp(bus_error_jmp, 1);
1746
1747 return 0;
1748}
1749
1750#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1751
1752void
1753byterev(unsigned char *val, int size)
1754{
1755 int t;
1756
1757 switch (size) {
1758 case 2:
1759 SWAP(val[0], val[1], t);
1760 break;
1761 case 4:
1762 SWAP(val[0], val[3], t);
1763 SWAP(val[1], val[2], t);
1764 break;
1765 case 8: /* is there really any use for this? */
1766 SWAP(val[0], val[7], t);
1767 SWAP(val[1], val[6], t);
1768 SWAP(val[2], val[5], t);
1769 SWAP(val[3], val[4], t);
1770 break;
1771 }
1772}
1773
1774static int brev;
1775static int mnoread;
1776
1777static char *memex_help_string =
1778 "Memory examine command usage:\n"
1779 "m [addr] [flags] examine/change memory\n"
1780 " addr is optional. will start where left off.\n"
1781 " flags may include chars from this set:\n"
1782 " b modify by bytes (default)\n"
1783 " w modify by words (2 byte)\n"
1784 " l modify by longs (4 byte)\n"
1785 " d modify by doubleword (8 byte)\n"
1786 " r toggle reverse byte order mode\n"
1787 " n do not read memory (for i/o spaces)\n"
1788 " . ok to read (default)\n"
1789 "NOTE: flags are saved as defaults\n"
1790 "";
1791
1792static char *memex_subcmd_help_string =
1793 "Memory examine subcommands:\n"
1794 " hexval write this val to current location\n"
1795 " 'string' write chars from string to this location\n"
1796 " ' increment address\n"
1797 " ^ decrement address\n"
1798 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1799 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1800 " ` clear no-read flag\n"
1801 " ; stay at this addr\n"
1802 " v change to byte mode\n"
1803 " w change to word (2 byte) mode\n"
1804 " l change to long (4 byte) mode\n"
1805 " u change to doubleword (8 byte) mode\n"
1806 " m addr change current addr\n"
1807 " n toggle no-read flag\n"
1808 " r toggle byte reverse flag\n"
1809 " < count back up count bytes\n"
1810 " > count skip forward count bytes\n"
1811 " x exit this mode\n"
1812 "";
1813
1814void
1815memex(void)
1816{
1817 int cmd, inc, i, nslash;
1818 unsigned long n;
1819 unsigned char val[16];
1820
1821 scanhex((void *)&adrs);
1822 cmd = skipbl();
1823 if (cmd == '?') {
1824 printf(memex_help_string);
1825 return;
1826 } else {
1827 termch = cmd;
1828 }
1829 last_cmd = "m\n";
1830 while ((cmd = skipbl()) != '\n') {
1831 switch( cmd ){
1832 case 'b': size = 1; break;
1833 case 'w': size = 2; break;
1834 case 'l': size = 4; break;
1835 case 'd': size = 8; break;
1836 case 'r': brev = !brev; break;
1837 case 'n': mnoread = 1; break;
1838 case '.': mnoread = 0; break;
1839 }
1840 }
1841 if( size <= 0 )
1842 size = 1;
1843 else if( size > 8 )
1844 size = 8;
1845 for(;;){
1846 if (!mnoread)
1847 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001848 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 if (!mnoread) {
1850 if (brev)
1851 byterev(val, size);
1852 putchar(' ');
1853 for (i = 0; i < n; ++i)
1854 printf("%.2x", val[i]);
1855 for (; i < size; ++i)
1856 printf("%s", fault_chars[fault_type]);
1857 }
1858 putchar(' ');
1859 inc = size;
1860 nslash = 0;
1861 for(;;){
1862 if( scanhex(&n) ){
1863 for (i = 0; i < size; ++i)
1864 val[i] = n >> (i * 8);
1865 if (!brev)
1866 byterev(val, size);
1867 mwrite(adrs, val, size);
1868 inc = size;
1869 }
1870 cmd = skipbl();
1871 if (cmd == '\n')
1872 break;
1873 inc = 0;
1874 switch (cmd) {
1875 case '\'':
1876 for(;;){
1877 n = inchar();
1878 if( n == '\\' )
1879 n = bsesc();
1880 else if( n == '\'' )
1881 break;
1882 for (i = 0; i < size; ++i)
1883 val[i] = n >> (i * 8);
1884 if (!brev)
1885 byterev(val, size);
1886 mwrite(adrs, val, size);
1887 adrs += size;
1888 }
1889 adrs -= size;
1890 inc = size;
1891 break;
1892 case ',':
1893 adrs += size;
1894 break;
1895 case '.':
1896 mnoread = 0;
1897 break;
1898 case ';':
1899 break;
1900 case 'x':
1901 case EOF:
1902 scannl();
1903 return;
1904 case 'b':
1905 case 'v':
1906 size = 1;
1907 break;
1908 case 'w':
1909 size = 2;
1910 break;
1911 case 'l':
1912 size = 4;
1913 break;
1914 case 'u':
1915 size = 8;
1916 break;
1917 case '^':
1918 adrs -= size;
1919 break;
1920 break;
1921 case '/':
1922 if (nslash > 0)
1923 adrs -= 1 << nslash;
1924 else
1925 nslash = 0;
1926 nslash += 4;
1927 adrs += 1 << nslash;
1928 break;
1929 case '\\':
1930 if (nslash < 0)
1931 adrs += 1 << -nslash;
1932 else
1933 nslash = 0;
1934 nslash -= 4;
1935 adrs -= 1 << -nslash;
1936 break;
1937 case 'm':
1938 scanhex((void *)&adrs);
1939 break;
1940 case 'n':
1941 mnoread = 1;
1942 break;
1943 case 'r':
1944 brev = !brev;
1945 break;
1946 case '<':
1947 n = size;
1948 scanhex(&n);
1949 adrs -= n;
1950 break;
1951 case '>':
1952 n = size;
1953 scanhex(&n);
1954 adrs += n;
1955 break;
1956 case '?':
1957 printf(memex_subcmd_help_string);
1958 break;
1959 }
1960 }
1961 adrs += inc;
1962 }
1963}
1964
1965int
1966bsesc(void)
1967{
1968 int c;
1969
1970 c = inchar();
1971 switch( c ){
1972 case 'n': c = '\n'; break;
1973 case 'r': c = '\r'; break;
1974 case 'b': c = '\b'; break;
1975 case 't': c = '\t'; break;
1976 }
1977 return c;
1978}
1979
Olaf Hering7e5b5932006-03-08 20:40:28 +01001980static void xmon_rawdump (unsigned long adrs, long ndump)
1981{
1982 long n, m, r, nr;
1983 unsigned char temp[16];
1984
1985 for (n = ndump; n > 0;) {
1986 r = n < 16? n: 16;
1987 nr = mread(adrs, temp, r);
1988 adrs += nr;
1989 for (m = 0; m < r; ++m) {
1990 if (m < nr)
1991 printf("%.2x", temp[m]);
1992 else
1993 printf("%s", fault_chars[fault_type]);
1994 }
1995 n -= r;
1996 if (nr < r)
1997 break;
1998 }
1999 printf("\n");
2000}
2001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2003 || ('a' <= (c) && (c) <= 'f') \
2004 || ('A' <= (c) && (c) <= 'F'))
2005void
2006dump(void)
2007{
2008 int c;
2009
2010 c = inchar();
2011 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2012 termch = c;
2013 scanhex((void *)&adrs);
2014 if (termch != '\n')
2015 termch = 0;
2016 if (c == 'i') {
2017 scanhex(&nidump);
2018 if (nidump == 0)
2019 nidump = 16;
2020 else if (nidump > MAX_DUMP)
2021 nidump = MAX_DUMP;
2022 adrs += ppc_inst_dump(adrs, nidump, 1);
2023 last_cmd = "di\n";
Olaf Hering7e5b5932006-03-08 20:40:28 +01002024 } else if (c == 'r') {
2025 scanhex(&ndump);
2026 if (ndump == 0)
2027 ndump = 64;
2028 xmon_rawdump(adrs, ndump);
2029 adrs += ndump;
2030 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 } else {
2032 scanhex(&ndump);
2033 if (ndump == 0)
2034 ndump = 64;
2035 else if (ndump > MAX_DUMP)
2036 ndump = MAX_DUMP;
2037 prdump(adrs, ndump);
2038 adrs += ndump;
2039 last_cmd = "d\n";
2040 }
2041}
2042
2043void
2044prdump(unsigned long adrs, long ndump)
2045{
2046 long n, m, c, r, nr;
2047 unsigned char temp[16];
2048
2049 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002050 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 putchar(' ');
2052 r = n < 16? n: 16;
2053 nr = mread(adrs, temp, r);
2054 adrs += nr;
2055 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002056 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2057 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 if (m < nr)
2059 printf("%.2x", temp[m]);
2060 else
2061 printf("%s", fault_chars[fault_type]);
2062 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002063 for (; m < 16; ++m) {
2064 if ((m & (sizeof(long) - 1)) == 0)
2065 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 printf(" |");
2069 for (m = 0; m < r; ++m) {
2070 if (m < nr) {
2071 c = temp[m];
2072 putchar(' ' <= c && c <= '~'? c: '.');
2073 } else
2074 putchar(' ');
2075 }
2076 n -= r;
2077 for (; m < 16; ++m)
2078 putchar(' ');
2079 printf("|\n");
2080 if (nr < r)
2081 break;
2082 }
2083}
2084
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002085typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2086
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002088generic_inst_dump(unsigned long adr, long count, int praddr,
2089 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090{
2091 int nr, dotted;
2092 unsigned long first_adr;
2093 unsigned long inst, last_inst = 0;
2094 unsigned char val[4];
2095
2096 dotted = 0;
2097 for (first_adr = adr; count > 0; --count, adr += 4) {
2098 nr = mread(adr, val, 4);
2099 if (nr == 0) {
2100 if (praddr) {
2101 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002102 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 }
2104 break;
2105 }
2106 inst = GETWORD(val);
2107 if (adr > first_adr && inst == last_inst) {
2108 if (!dotted) {
2109 printf(" ...\n");
2110 dotted = 1;
2111 }
2112 continue;
2113 }
2114 dotted = 0;
2115 last_inst = inst;
2116 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002117 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002119 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 printf("\n");
2121 }
2122 return adr - first_adr;
2123}
2124
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002125int
2126ppc_inst_dump(unsigned long adr, long count, int praddr)
2127{
2128 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2129}
2130
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131void
2132print_address(unsigned long addr)
2133{
2134 xmon_print_symbol(addr, "\t# ", "");
2135}
2136
2137
2138/*
2139 * Memory operations - move, set, print differences
2140 */
2141static unsigned long mdest; /* destination address */
2142static unsigned long msrc; /* source address */
2143static unsigned long mval; /* byte value to set memory to */
2144static unsigned long mcount; /* # bytes to affect */
2145static unsigned long mdiffs; /* max # differences to print */
2146
2147void
2148memops(int cmd)
2149{
2150 scanhex((void *)&mdest);
2151 if( termch != '\n' )
2152 termch = 0;
2153 scanhex((void *)(cmd == 's'? &mval: &msrc));
2154 if( termch != '\n' )
2155 termch = 0;
2156 scanhex((void *)&mcount);
2157 switch( cmd ){
2158 case 'm':
2159 memmove((void *)mdest, (void *)msrc, mcount);
2160 break;
2161 case 's':
2162 memset((void *)mdest, mval, mcount);
2163 break;
2164 case 'd':
2165 if( termch != '\n' )
2166 termch = 0;
2167 scanhex((void *)&mdiffs);
2168 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2169 break;
2170 }
2171}
2172
2173void
2174memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2175{
2176 unsigned n, prt;
2177
2178 prt = 0;
2179 for( n = nb; n > 0; --n )
2180 if( *p1++ != *p2++ )
2181 if( ++prt <= maxpr )
2182 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2183 p1[-1], p2 - 1, p2[-1]);
2184 if( prt > maxpr )
2185 printf("Total of %d differences\n", prt);
2186}
2187
2188static unsigned mend;
2189static unsigned mask;
2190
2191void
2192memlocate(void)
2193{
2194 unsigned a, n;
2195 unsigned char val[4];
2196
2197 last_cmd = "ml";
2198 scanhex((void *)&mdest);
2199 if (termch != '\n') {
2200 termch = 0;
2201 scanhex((void *)&mend);
2202 if (termch != '\n') {
2203 termch = 0;
2204 scanhex((void *)&mval);
2205 mask = ~0;
2206 if (termch != '\n') termch = 0;
2207 scanhex((void *)&mask);
2208 }
2209 }
2210 n = 0;
2211 for (a = mdest; a < mend; a += 4) {
2212 if (mread(a, val, 4) == 4
2213 && ((GETWORD(val) ^ mval) & mask) == 0) {
2214 printf("%.16x: %.16x\n", a, GETWORD(val));
2215 if (++n >= 10)
2216 break;
2217 }
2218 }
2219}
2220
2221static unsigned long mskip = 0x1000;
2222static unsigned long mlim = 0xffffffff;
2223
2224void
2225memzcan(void)
2226{
2227 unsigned char v;
2228 unsigned a;
2229 int ok, ook;
2230
2231 scanhex(&mdest);
2232 if (termch != '\n') termch = 0;
2233 scanhex(&mskip);
2234 if (termch != '\n') termch = 0;
2235 scanhex(&mlim);
2236 ook = 0;
2237 for (a = mdest; a < mlim; a += mskip) {
2238 ok = mread(a, &v, 1);
2239 if (ok && !ook) {
2240 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 } else if (!ok && ook)
2242 printf("%.8x\n", a - mskip);
2243 ook = ok;
2244 if (a + mskip < a)
2245 break;
2246 }
2247 if (ook)
2248 printf("%.8x\n", a - mskip);
2249}
2250
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002251void proccall(void)
2252{
2253 unsigned long args[8];
2254 unsigned long ret;
2255 int i;
2256 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2257 unsigned long, unsigned long, unsigned long,
2258 unsigned long, unsigned long, unsigned long);
2259 callfunc_t func;
2260
2261 if (!scanhex(&adrs))
2262 return;
2263 if (termch != '\n')
2264 termch = 0;
2265 for (i = 0; i < 8; ++i)
2266 args[i] = 0;
2267 for (i = 0; i < 8; ++i) {
2268 if (!scanhex(&args[i]) || termch == '\n')
2269 break;
2270 termch = 0;
2271 }
2272 func = (callfunc_t) adrs;
2273 ret = 0;
2274 if (setjmp(bus_error_jmp) == 0) {
2275 catch_memory_errors = 1;
2276 sync();
2277 ret = func(args[0], args[1], args[2], args[3],
2278 args[4], args[5], args[6], args[7]);
2279 sync();
2280 printf("return value is %x\n", ret);
2281 } else {
2282 printf("*** %x exception occurred\n", fault_except);
2283 }
2284 catch_memory_errors = 0;
2285}
2286
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287/* Input scanning routines */
2288int
2289skipbl(void)
2290{
2291 int c;
2292
2293 if( termch != 0 ){
2294 c = termch;
2295 termch = 0;
2296 } else
2297 c = inchar();
2298 while( c == ' ' || c == '\t' )
2299 c = inchar();
2300 return c;
2301}
2302
2303#define N_PTREGS 44
2304static char *regnames[N_PTREGS] = {
2305 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2306 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2307 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2308 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002309 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2310#ifdef CONFIG_PPC64
2311 "softe",
2312#else
2313 "mq",
2314#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 "trap", "dar", "dsisr", "res"
2316};
2317
2318int
2319scanhex(unsigned long *vp)
2320{
2321 int c, d;
2322 unsigned long v;
2323
2324 c = skipbl();
2325 if (c == '%') {
2326 /* parse register name */
2327 char regname[8];
2328 int i;
2329
2330 for (i = 0; i < sizeof(regname) - 1; ++i) {
2331 c = inchar();
2332 if (!isalnum(c)) {
2333 termch = c;
2334 break;
2335 }
2336 regname[i] = c;
2337 }
2338 regname[i] = 0;
2339 for (i = 0; i < N_PTREGS; ++i) {
2340 if (strcmp(regnames[i], regname) == 0) {
2341 if (xmon_regs == NULL) {
2342 printf("regs not available\n");
2343 return 0;
2344 }
2345 *vp = ((unsigned long *)xmon_regs)[i];
2346 return 1;
2347 }
2348 }
2349 printf("invalid register name '%%%s'\n", regname);
2350 return 0;
2351 }
2352
2353 /* skip leading "0x" if any */
2354
2355 if (c == '0') {
2356 c = inchar();
2357 if (c == 'x') {
2358 c = inchar();
2359 } else {
2360 d = hexdigit(c);
2361 if (d == EOF) {
2362 termch = c;
2363 *vp = 0;
2364 return 1;
2365 }
2366 }
2367 } else if (c == '$') {
2368 int i;
2369 for (i=0; i<63; i++) {
2370 c = inchar();
2371 if (isspace(c)) {
2372 termch = c;
2373 break;
2374 }
2375 tmpstr[i] = c;
2376 }
2377 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002378 *vp = 0;
2379 if (setjmp(bus_error_jmp) == 0) {
2380 catch_memory_errors = 1;
2381 sync();
2382 *vp = kallsyms_lookup_name(tmpstr);
2383 sync();
2384 }
2385 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 if (!(*vp)) {
2387 printf("unknown symbol '%s'\n", tmpstr);
2388 return 0;
2389 }
2390 return 1;
2391 }
2392
2393 d = hexdigit(c);
2394 if (d == EOF) {
2395 termch = c;
2396 return 0;
2397 }
2398 v = 0;
2399 do {
2400 v = (v << 4) + d;
2401 c = inchar();
2402 d = hexdigit(c);
2403 } while (d != EOF);
2404 termch = c;
2405 *vp = v;
2406 return 1;
2407}
2408
2409void
2410scannl(void)
2411{
2412 int c;
2413
2414 c = termch;
2415 termch = 0;
2416 while( c != '\n' )
2417 c = inchar();
2418}
2419
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002420int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421{
2422 if( '0' <= c && c <= '9' )
2423 return c - '0';
2424 if( 'A' <= c && c <= 'F' )
2425 return c - ('A' - 10);
2426 if( 'a' <= c && c <= 'f' )
2427 return c - ('a' - 10);
2428 return EOF;
2429}
2430
2431void
2432getstring(char *s, int size)
2433{
2434 int c;
2435
2436 c = skipbl();
2437 do {
2438 if( size > 1 ){
2439 *s++ = c;
2440 --size;
2441 }
2442 c = inchar();
2443 } while( c != ' ' && c != '\t' && c != '\n' );
2444 termch = c;
2445 *s = 0;
2446}
2447
2448static char line[256];
2449static char *lineptr;
2450
2451void
2452flush_input(void)
2453{
2454 lineptr = NULL;
2455}
2456
2457int
2458inchar(void)
2459{
2460 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002461 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 lineptr = NULL;
2463 return EOF;
2464 }
2465 lineptr = line;
2466 }
2467 return *lineptr++;
2468}
2469
2470void
2471take_input(char *str)
2472{
2473 lineptr = str;
2474}
2475
2476
2477static void
2478symbol_lookup(void)
2479{
2480 int type = inchar();
2481 unsigned long addr;
2482 static char tmp[64];
2483
2484 switch (type) {
2485 case 'a':
2486 if (scanhex(&addr))
2487 xmon_print_symbol(addr, ": ", "\n");
2488 termch = 0;
2489 break;
2490 case 's':
2491 getstring(tmp, 64);
2492 if (setjmp(bus_error_jmp) == 0) {
2493 catch_memory_errors = 1;
2494 sync();
2495 addr = kallsyms_lookup_name(tmp);
2496 if (addr)
2497 printf("%s: %lx\n", tmp, addr);
2498 else
2499 printf("Symbol '%s' not found.\n", tmp);
2500 sync();
2501 }
2502 catch_memory_errors = 0;
2503 termch = 0;
2504 break;
2505 }
2506}
2507
2508
2509/* Print an address in numeric and symbolic form (if possible) */
2510static void xmon_print_symbol(unsigned long address, const char *mid,
2511 const char *after)
2512{
2513 char *modname;
2514 const char *name = NULL;
2515 unsigned long offset, size;
2516
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002517 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 if (setjmp(bus_error_jmp) == 0) {
2519 catch_memory_errors = 1;
2520 sync();
2521 name = kallsyms_lookup(address, &size, &offset, &modname,
2522 tmpstr);
2523 sync();
2524 /* wait a little while to see if we get a machine check */
2525 __delay(200);
2526 }
2527
2528 catch_memory_errors = 0;
2529
2530 if (name) {
2531 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2532 if (modname)
2533 printf(" [%s]", modname);
2534 }
2535 printf("%s", after);
2536}
2537
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002538#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539static void dump_slb(void)
2540{
2541 int i;
2542 unsigned long tmp;
2543
2544 printf("SLB contents of cpu %x\n", smp_processor_id());
2545
2546 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2547 asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
2548 printf("%02d %016lx ", i, tmp);
2549
2550 asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
2551 printf("%016lx\n", tmp);
2552 }
2553}
2554
2555static void dump_stab(void)
2556{
2557 int i;
2558 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2559
2560 printf("Segment table contents of cpu %x\n", smp_processor_id());
2561
2562 for (i = 0; i < PAGE_SIZE/16; i++) {
2563 unsigned long a, b;
2564
2565 a = *tmp++;
2566 b = *tmp++;
2567
2568 if (a || b) {
2569 printf("%03d %016lx ", i, a);
2570 printf("%016lx\n", b);
2571 }
2572 }
2573}
2574
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002575void dump_segments(void)
2576{
2577 if (cpu_has_feature(CPU_FTR_SLB))
2578 dump_slb();
2579 else
2580 dump_stab();
2581}
2582#endif
2583
2584#ifdef CONFIG_PPC_STD_MMU_32
2585void dump_segments(void)
2586{
2587 int i;
2588
2589 printf("sr0-15 =");
2590 for (i = 0; i < 16; ++i)
2591 printf(" %x", mfsrin(i));
2592 printf("\n");
2593}
2594#endif
2595
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002596#ifdef CONFIG_44x
2597static void dump_tlb_44x(void)
2598{
2599 int i;
2600
2601 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2602 unsigned long w0,w1,w2;
2603 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2604 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2605 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2606 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2607 if (w0 & PPC44x_TLB_VALID) {
2608 printf("V %08x -> %01x%08x %c%c%c%c%c",
2609 w0 & PPC44x_TLB_EPN_MASK,
2610 w1 & PPC44x_TLB_ERPN_MASK,
2611 w1 & PPC44x_TLB_RPN_MASK,
2612 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2613 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2614 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2615 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2616 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2617 }
2618 printf("\n");
2619 }
2620}
2621#endif /* CONFIG_44x */
Olaf Heringb13cfd172005-08-04 19:26:42 +02002622void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002624#ifdef CONFIG_PPC_ISERIES
2625 if (firmware_has_feature(FW_FEATURE_ISERIES))
2626 return;
2627#endif
Olaf Heringb13cfd172005-08-04 19:26:42 +02002628 if (enable) {
2629 __debugger = xmon;
2630 __debugger_ipi = xmon_ipi;
2631 __debugger_bpt = xmon_bpt;
2632 __debugger_sstep = xmon_sstep;
2633 __debugger_iabr_match = xmon_iabr_match;
2634 __debugger_dabr_match = xmon_dabr_match;
2635 __debugger_fault_handler = xmon_fault_handler;
2636 } else {
2637 __debugger = NULL;
2638 __debugger_ipi = NULL;
2639 __debugger_bpt = NULL;
2640 __debugger_sstep = NULL;
2641 __debugger_iabr_match = NULL;
2642 __debugger_dabr_match = NULL;
2643 __debugger_fault_handler = NULL;
2644 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002645 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002647
2648#ifdef CONFIG_MAGIC_SYSRQ
David Howells7d12e782006-10-05 14:55:46 +01002649static void sysrq_handle_xmon(int key, struct tty_struct *tty)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002650{
2651 /* ensure xmon is enabled */
2652 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002653 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002654}
2655
2656static struct sysrq_key_op sysrq_xmon_op =
2657{
2658 .handler = sysrq_handle_xmon,
2659 .help_msg = "Xmon",
2660 .action_msg = "Entering xmon",
2661};
2662
2663static int __init setup_xmon_sysrq(void)
2664{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002665#ifdef CONFIG_PPC_ISERIES
2666 if (firmware_has_feature(FW_FEATURE_ISERIES))
2667 return 0;
2668#endif
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002669 register_sysrq_key('x', &sysrq_xmon_op);
2670 return 0;
2671}
2672__initcall(setup_xmon_sysrq);
2673#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002674
Olaf Heringf5e6a282007-06-24 16:57:08 +10002675static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002676
2677static int __init early_parse_xmon(char *p)
2678{
2679 if (!p || strncmp(p, "early", 5) == 0) {
2680 /* just "xmon" is equivalent to "xmon=early" */
2681 xmon_init(1);
2682 xmon_early = 1;
2683 } else if (strncmp(p, "on", 2) == 0)
2684 xmon_init(1);
2685 else if (strncmp(p, "off", 3) == 0)
2686 xmon_off = 1;
2687 else if (strncmp(p, "nobt", 4) == 0)
2688 xmon_no_auto_backtrace = 1;
2689 else
2690 return 1;
2691
2692 return 0;
2693}
2694early_param("xmon", early_parse_xmon);
2695
2696void __init xmon_setup(void)
2697{
2698#ifdef CONFIG_XMON_DEFAULT
2699 if (!xmon_off)
2700 xmon_init(1);
2701#endif
2702 if (xmon_early)
2703 debugger(NULL);
2704}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002705
Arnd Bergmanne0555952006-11-27 19:18:55 +01002706#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002707
2708struct spu_info {
2709 struct spu *spu;
2710 u64 saved_mfc_sr1_RW;
2711 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002712 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002713 u8 stopped_ok;
2714};
2715
2716#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2717
2718static struct spu_info spu_info[XMON_NUM_SPUS];
2719
2720void xmon_register_spus(struct list_head *list)
2721{
2722 struct spu *spu;
2723
2724 list_for_each_entry(spu, list, full_list) {
2725 if (spu->number >= XMON_NUM_SPUS) {
2726 WARN_ON(1);
2727 continue;
2728 }
2729
2730 spu_info[spu->number].spu = spu;
2731 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002732 spu_info[spu->number].dump_addr = (unsigned long)
2733 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002734 }
2735}
2736
2737static void stop_spus(void)
2738{
2739 struct spu *spu;
2740 int i;
2741 u64 tmp;
2742
2743 for (i = 0; i < XMON_NUM_SPUS; i++) {
2744 if (!spu_info[i].spu)
2745 continue;
2746
2747 if (setjmp(bus_error_jmp) == 0) {
2748 catch_memory_errors = 1;
2749 sync();
2750
2751 spu = spu_info[i].spu;
2752
2753 spu_info[i].saved_spu_runcntl_RW =
2754 in_be32(&spu->problem->spu_runcntl_RW);
2755
2756 tmp = spu_mfc_sr1_get(spu);
2757 spu_info[i].saved_mfc_sr1_RW = tmp;
2758
2759 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2760 spu_mfc_sr1_set(spu, tmp);
2761
2762 sync();
2763 __delay(200);
2764
2765 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01002766
2767 printf("Stopped spu %.2d (was %s)\n", i,
2768 spu_info[i].saved_spu_runcntl_RW ?
2769 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002770 } else {
2771 catch_memory_errors = 0;
2772 printf("*** Error stopping spu %.2d\n", i);
2773 }
2774 catch_memory_errors = 0;
2775 }
2776}
2777
2778static void restart_spus(void)
2779{
2780 struct spu *spu;
2781 int i;
2782
2783 for (i = 0; i < XMON_NUM_SPUS; i++) {
2784 if (!spu_info[i].spu)
2785 continue;
2786
2787 if (!spu_info[i].stopped_ok) {
2788 printf("*** Error, spu %d was not successfully stopped"
2789 ", not restarting\n", i);
2790 continue;
2791 }
2792
2793 if (setjmp(bus_error_jmp) == 0) {
2794 catch_memory_errors = 1;
2795 sync();
2796
2797 spu = spu_info[i].spu;
2798 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2799 out_be32(&spu->problem->spu_runcntl_RW,
2800 spu_info[i].saved_spu_runcntl_RW);
2801
2802 sync();
2803 __delay(200);
2804
2805 printf("Restarted spu %.2d\n", i);
2806 } else {
2807 catch_memory_errors = 0;
2808 printf("*** Error restarting spu %.2d\n", i);
2809 }
2810 catch_memory_errors = 0;
2811 }
2812}
2813
Michael Ellermana8984972006-10-24 18:31:28 +02002814#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01002815#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02002816do { \
2817 if (setjmp(bus_error_jmp) == 0) { \
2818 catch_memory_errors = 1; \
2819 sync(); \
2820 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01002821 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02002822 sync(); \
2823 __delay(200); \
2824 } else { \
2825 catch_memory_errors = 0; \
2826 printf(" %-*s = *** Error reading field.\n", \
2827 DUMP_WIDTH, #field); \
2828 } \
2829 catch_memory_errors = 0; \
2830} while (0)
2831
Michael Ellerman437a0702006-11-23 00:46:39 +01002832#define DUMP_FIELD(obj, format, field) \
2833 DUMP_VALUE(format, field, obj->field)
2834
Michael Ellermana8984972006-10-24 18:31:28 +02002835static void dump_spu_fields(struct spu *spu)
2836{
2837 printf("Dumping spu fields at address %p:\n", spu);
2838
2839 DUMP_FIELD(spu, "0x%x", number);
2840 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02002841 DUMP_FIELD(spu, "0x%lx", local_store_phys);
2842 DUMP_FIELD(spu, "0x%p", local_store);
2843 DUMP_FIELD(spu, "0x%lx", ls_size);
2844 DUMP_FIELD(spu, "0x%x", node);
2845 DUMP_FIELD(spu, "0x%lx", flags);
2846 DUMP_FIELD(spu, "0x%lx", dar);
2847 DUMP_FIELD(spu, "0x%lx", dsisr);
2848 DUMP_FIELD(spu, "%d", class_0_pending);
2849 DUMP_FIELD(spu, "0x%lx", irqs[0]);
2850 DUMP_FIELD(spu, "0x%lx", irqs[1]);
2851 DUMP_FIELD(spu, "0x%lx", irqs[2]);
2852 DUMP_FIELD(spu, "0x%x", slb_replace);
2853 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02002854 DUMP_FIELD(spu, "0x%p", mm);
2855 DUMP_FIELD(spu, "0x%p", ctx);
2856 DUMP_FIELD(spu, "0x%p", rq);
2857 DUMP_FIELD(spu, "0x%p", timestamp);
2858 DUMP_FIELD(spu, "0x%lx", problem_phys);
2859 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01002860 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
2861 in_be32(&spu->problem->spu_runcntl_RW));
2862 DUMP_VALUE("0x%x", problem->spu_status_R,
2863 in_be32(&spu->problem->spu_status_R));
2864 DUMP_VALUE("0x%x", problem->spu_npc_RW,
2865 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02002866 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01002867 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02002868}
2869
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002870int
2871spu_inst_dump(unsigned long adr, long count, int praddr)
2872{
2873 return generic_inst_dump(adr, count, praddr, print_insn_spu);
2874}
2875
2876static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01002877{
2878 unsigned long offset, addr, ls_addr;
2879
2880 if (setjmp(bus_error_jmp) == 0) {
2881 catch_memory_errors = 1;
2882 sync();
2883 ls_addr = (unsigned long)spu_info[num].spu->local_store;
2884 sync();
2885 __delay(200);
2886 } else {
2887 catch_memory_errors = 0;
2888 printf("*** Error: accessing spu info for spu %d\n", num);
2889 return;
2890 }
2891 catch_memory_errors = 0;
2892
2893 if (scanhex(&offset))
2894 addr = ls_addr + offset;
2895 else
2896 addr = spu_info[num].dump_addr;
2897
2898 if (addr >= ls_addr + LS_SIZE) {
2899 printf("*** Error: address outside of local store\n");
2900 return;
2901 }
2902
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002903 switch (subcmd) {
2904 case 'i':
2905 addr += spu_inst_dump(addr, 16, 1);
2906 last_cmd = "sdi\n";
2907 break;
2908 default:
2909 prdump(addr, 64);
2910 addr += 64;
2911 last_cmd = "sd\n";
2912 break;
2913 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01002914
2915 spu_info[num].dump_addr = addr;
2916}
2917
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002918static int do_spu_cmd(void)
2919{
Michael Ellerman24a24c82006-11-23 00:46:41 +01002920 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002921 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002922
2923 cmd = inchar();
2924 switch (cmd) {
2925 case 's':
2926 stop_spus();
2927 break;
2928 case 'r':
2929 restart_spus();
2930 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002931 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002932 subcmd = inchar();
2933 if (isxdigit(subcmd) || subcmd == '\n')
2934 termch = subcmd;
2935 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01002936 scanhex(&num);
2937 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02002938 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01002939 return 0;
2940 }
2941
2942 switch (cmd) {
2943 case 'f':
2944 dump_spu_fields(spu_info[num].spu);
2945 break;
2946 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002947 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01002948 break;
2949 }
2950
Michael Ellermana8984972006-10-24 18:31:28 +02002951 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002952 default:
2953 return -1;
2954 }
2955
2956 return 0;
2957}
Arnd Bergmanne0555952006-11-27 19:18:55 +01002958#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002959static int do_spu_cmd(void)
2960{
2961 return -1;
2962}
2963#endif