blob: b481db1dacb4a7b3f2c35e49a0789612bbc591a7 [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
Olaf Hering26c8af52006-09-08 16:29:21 +0200156int xmon_no_auto_backtrace;
157
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000158extern void xmon_enter(void);
159extern void xmon_leave(void);
160
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000161extern long setjmp(long *);
162extern void longjmp(long *, long);
163extern void xmon_save_regs(struct pt_regs *);
164
165#ifdef CONFIG_PPC64
166#define REG "%.16lx"
167#define REGS_PER_LINE 4
168#define LAST_VOLATILE 13
169#else
170#define REG "%.8lx"
171#define REGS_PER_LINE 8
172#define LAST_VOLATILE 12
173#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
176
177#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
178 || ('a' <= (c) && (c) <= 'f') \
179 || ('A' <= (c) && (c) <= 'F'))
180#define isalnum(c) (('0' <= (c) && (c) <= '9') \
181 || ('a' <= (c) && (c) <= 'z') \
182 || ('A' <= (c) && (c) <= 'Z'))
183#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
184
185static char *help_string = "\
186Commands:\n\
187 b show breakpoints\n\
188 bd set data breakpoint\n\
189 bi set instruction breakpoint\n\
190 bc clear breakpoint\n"
191#ifdef CONFIG_SMP
192 "\
193 c print cpus stopped in xmon\n\
194 c# try to switch to cpu number h (in hex)\n"
195#endif
196 "\
197 C checksum\n\
198 d dump bytes\n\
199 di dump instructions\n\
200 df dump float values\n\
201 dd dump double values\n\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100202 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 e print exception information\n\
204 f flush cache\n\
205 la lookup symbol+offset of specified address\n\
206 ls lookup address of specified symbol\n\
207 m examine/change memory\n\
208 mm move a block of memory\n\
209 ms set a block of memory\n\
210 md compare two blocks of memory\n\
211 ml locate a block of memory\n\
212 mz zero a block of memory\n\
213 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000214 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200216 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100217#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200218" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200219 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100220 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900221 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100222 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200223#endif
224" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000227 X exit monitor and dont recover\n"
228#ifdef CONFIG_PPC64
229" u dump segment table or SLB\n"
230#endif
231#ifdef CONFIG_PPC_STD_MMU_32
232" u dump segment registers\n"
233#endif
234" ? help\n"
235" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 zh halt\n"
237;
238
239static struct pt_regs *xmon_regs;
240
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000241static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242{
243 asm volatile("sync; isync");
244}
245
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000246static inline void store_inst(void *p)
247{
248 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000251static inline void cflush(void *p)
252{
253 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
254}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000256static inline void cinval(void *p)
257{
258 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
259}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
261/*
262 * Disable surveillance (the service processor watchdog function)
263 * while we are in xmon.
264 * XXX we should re-enable it when we leave. :)
265 */
266#define SURVEILLANCE_TOKEN 9000
267
268static inline void disable_surveillance(void)
269{
270#ifdef CONFIG_PPC_PSERIES
271 /* Since this can't be a module, args should end up below 4GB. */
272 static struct rtas_args args;
273
274 /*
275 * At this point we have got all the cpus we can into
276 * xmon, so there is hopefully no other cpu calling RTAS
277 * at the moment, even though we don't take rtas.lock.
278 * If we did try to take rtas.lock there would be a
279 * real possibility of deadlock.
280 */
281 args.token = rtas_token("set-indicator");
282 if (args.token == RTAS_UNKNOWN_SERVICE)
283 return;
284 args.nargs = 3;
285 args.nret = 1;
286 args.rets = &args.args[3];
287 args.args[0] = SURVEILLANCE_TOKEN;
288 args.args[1] = 0;
289 args.args[2] = 0;
290 enter_rtas(__pa(&args));
291#endif /* CONFIG_PPC_PSERIES */
292}
293
294#ifdef CONFIG_SMP
295static int xmon_speaker;
296
297static void get_output_lock(void)
298{
299 int me = smp_processor_id() + 0x100;
300 int last_speaker = 0, prev;
301 long timeout;
302
303 if (xmon_speaker == me)
304 return;
305 for (;;) {
306 if (xmon_speaker == 0) {
307 last_speaker = cmpxchg(&xmon_speaker, 0, me);
308 if (last_speaker == 0)
309 return;
310 }
311 timeout = 10000000;
312 while (xmon_speaker == last_speaker) {
313 if (--timeout > 0)
314 continue;
315 /* hostile takeover */
316 prev = cmpxchg(&xmon_speaker, last_speaker, me);
317 if (prev == last_speaker)
318 return;
319 break;
320 }
321 }
322}
323
324static void release_output_lock(void)
325{
326 xmon_speaker = 0;
327}
328#endif
329
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000330static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
332 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 struct bpt *bp;
334 long recurse_jmp[JMP_BUF_LEN];
335 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100336 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337#ifdef CONFIG_SMP
338 int cpu;
339 int secondary;
340 unsigned long timeout;
341#endif
342
Anton Blanchardf13659e2007-03-21 01:48:34 +1100343 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 bp = in_breakpoint_table(regs->nip, &offset);
346 if (bp != NULL) {
347 regs->nip = bp->address + offset;
348 atomic_dec(&bp->ref_count);
349 }
350
351 remove_cpu_bpts();
352
353#ifdef CONFIG_SMP
354 cpu = smp_processor_id();
355 if (cpu_isset(cpu, cpus_in_xmon)) {
356 get_output_lock();
357 excprint(regs);
358 printf("cpu 0x%x: Exception %lx %s in xmon, "
359 "returning to main loop\n",
360 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000361 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 longjmp(xmon_fault_jmp[cpu], 1);
363 }
364
365 if (setjmp(recurse_jmp) != 0) {
366 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000367 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 printf("xmon: WARNING: bad recursive fault "
369 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000370 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 goto waiting;
372 }
373 secondary = !(xmon_taken && cpu == xmon_owner);
374 goto cmdloop;
375 }
376
377 xmon_fault_jmp[cpu] = recurse_jmp;
378 cpu_set(cpu, cpus_in_xmon);
379
380 bp = NULL;
381 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
382 bp = at_breakpoint(regs->nip);
383 if (bp || (regs->msr & MSR_RI) == 0)
384 fromipi = 0;
385
386 if (!fromipi) {
387 get_output_lock();
388 excprint(regs);
389 if (bp) {
390 printf("cpu 0x%x stopped at breakpoint 0x%x (",
391 cpu, BP_NUM(bp));
392 xmon_print_symbol(regs->nip, " ", ")\n");
393 }
394 if ((regs->msr & MSR_RI) == 0)
395 printf("WARNING: exception is not recoverable, "
396 "can't continue\n");
397 release_output_lock();
398 }
399
400 waiting:
401 secondary = 1;
402 while (secondary && !xmon_gate) {
403 if (in_xmon == 0) {
404 if (fromipi)
405 goto leave;
406 secondary = test_and_set_bit(0, &in_xmon);
407 }
408 barrier();
409 }
410
411 if (!secondary && !xmon_gate) {
412 /* we are the first cpu to come in */
413 /* interrupt other cpu(s) */
414 int ncpus = num_online_cpus();
415
416 xmon_owner = cpu;
417 mb();
418 if (ncpus > 1) {
419 smp_send_debugger_break(MSG_ALL_BUT_SELF);
420 /* wait for other cpus to come in */
421 for (timeout = 100000000; timeout != 0; --timeout) {
422 if (cpus_weight(cpus_in_xmon) >= ncpus)
423 break;
424 barrier();
425 }
426 }
427 remove_bpts();
428 disable_surveillance();
429 /* for breakpoint or single step, print the current instr. */
430 if (bp || TRAP(regs) == 0xd00)
431 ppc_inst_dump(regs->nip, 1, 0);
432 printf("enter ? for help\n");
433 mb();
434 xmon_gate = 1;
435 barrier();
436 }
437
438 cmdloop:
439 while (in_xmon) {
440 if (secondary) {
441 if (cpu == xmon_owner) {
442 if (!test_and_set_bit(0, &xmon_taken)) {
443 secondary = 0;
444 continue;
445 }
446 /* missed it */
447 while (cpu == xmon_owner)
448 barrier();
449 }
450 barrier();
451 } else {
452 cmd = cmds(regs);
453 if (cmd != 0) {
454 /* exiting xmon */
455 insert_bpts();
456 xmon_gate = 0;
457 wmb();
458 in_xmon = 0;
459 break;
460 }
461 /* have switched to some other cpu */
462 secondary = 1;
463 }
464 }
465 leave:
466 cpu_clear(cpu, cpus_in_xmon);
467 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468#else
469 /* UP is simple... */
470 if (in_xmon) {
471 printf("Exception %lx %s in xmon, returning to main loop\n",
472 regs->trap, getvecname(TRAP(regs)));
473 longjmp(xmon_fault_jmp[0], 1);
474 }
475 if (setjmp(recurse_jmp) == 0) {
476 xmon_fault_jmp[0] = recurse_jmp;
477 in_xmon = 1;
478
479 excprint(regs);
480 bp = at_breakpoint(regs->nip);
481 if (bp) {
482 printf("Stopped at breakpoint %x (", BP_NUM(bp));
483 xmon_print_symbol(regs->nip, " ", ")\n");
484 }
485 if ((regs->msr & MSR_RI) == 0)
486 printf("WARNING: exception is not recoverable, "
487 "can't continue\n");
488 remove_bpts();
489 disable_surveillance();
490 /* for breakpoint or single step, print the current instr. */
491 if (bp || TRAP(regs) == 0xd00)
492 ppc_inst_dump(regs->nip, 1, 0);
493 printf("enter ? for help\n");
494 }
495
496 cmd = cmds(regs);
497
498 insert_bpts();
499 in_xmon = 0;
500#endif
501
502 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
503 bp = at_breakpoint(regs->nip);
504 if (bp != NULL) {
505 int stepped = emulate_step(regs, bp->instr[0]);
506 if (stepped == 0) {
507 regs->nip = (unsigned long) &bp->instr[0];
508 atomic_inc(&bp->ref_count);
509 } else if (stepped < 0) {
510 printf("Couldn't single-step %s instruction\n",
511 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
512 }
513 }
514 }
515
516 insert_cpu_bpts();
517
Anton Blanchardf13659e2007-03-21 01:48:34 +1100518 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000520 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
523int xmon(struct pt_regs *excp)
524{
525 struct pt_regs regs;
526
527 if (excp == NULL) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000528 xmon_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 excp = &regs;
530 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return xmon_core(excp, 0);
533}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000534EXPORT_SYMBOL(xmon);
535
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000536irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000537{
538 unsigned long flags;
539 local_irq_save(flags);
540 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000541 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000542 local_irq_restore(flags);
543 return IRQ_HANDLED;
544}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000546static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
548 struct bpt *bp;
549 unsigned long offset;
550
551 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
552 return 0;
553
554 /* Are we at the trap at bp->instr[1] for some bp? */
555 bp = in_breakpoint_table(regs->nip, &offset);
556 if (bp != NULL && offset == 4) {
557 regs->nip = bp->address + 4;
558 atomic_dec(&bp->ref_count);
559 return 1;
560 }
561
562 /* Are we at a breakpoint? */
563 bp = at_breakpoint(regs->nip);
564 if (!bp)
565 return 0;
566
567 xmon_core(regs, 0);
568
569 return 1;
570}
571
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000572static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 if (user_mode(regs))
575 return 0;
576 xmon_core(regs, 0);
577 return 1;
578}
579
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000580static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
582 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
583 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000584 if (dabr.enabled == 0)
585 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 xmon_core(regs, 0);
587 return 1;
588}
589
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000590static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
592 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
593 return 0;
594 if (iabr == 0)
595 return 0;
596 xmon_core(regs, 0);
597 return 1;
598}
599
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000600static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602#ifdef CONFIG_SMP
603 if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
604 xmon_core(regs, 1);
605#endif
606 return 0;
607}
608
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000609static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
611 struct bpt *bp;
612 unsigned long offset;
613
614 if (in_xmon && catch_memory_errors)
615 handle_fault(regs); /* doesn't return */
616
617 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
618 bp = in_breakpoint_table(regs->nip, &offset);
619 if (bp != NULL) {
620 regs->nip = bp->address + offset;
621 atomic_dec(&bp->ref_count);
622 }
623 }
624
625 return 0;
626}
627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628static struct bpt *at_breakpoint(unsigned long pc)
629{
630 int i;
631 struct bpt *bp;
632
633 bp = bpts;
634 for (i = 0; i < NBPTS; ++i, ++bp)
635 if (bp->enabled && pc == bp->address)
636 return bp;
637 return NULL;
638}
639
640static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
641{
642 unsigned long off;
643
644 off = nip - (unsigned long) bpts;
645 if (off >= sizeof(bpts))
646 return NULL;
647 off %= sizeof(struct bpt);
648 if (off != offsetof(struct bpt, instr[0])
649 && off != offsetof(struct bpt, instr[1]))
650 return NULL;
651 *offp = off - offsetof(struct bpt, instr[0]);
652 return (struct bpt *) (nip - off);
653}
654
655static struct bpt *new_breakpoint(unsigned long a)
656{
657 struct bpt *bp;
658
659 a &= ~3UL;
660 bp = at_breakpoint(a);
661 if (bp)
662 return bp;
663
664 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
665 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
666 bp->address = a;
667 bp->instr[1] = bpinstr;
668 store_inst(&bp->instr[1]);
669 return bp;
670 }
671 }
672
673 printf("Sorry, no free breakpoints. Please clear one first.\n");
674 return NULL;
675}
676
677static void insert_bpts(void)
678{
679 int i;
680 struct bpt *bp;
681
682 bp = bpts;
683 for (i = 0; i < NBPTS; ++i, ++bp) {
684 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
685 continue;
686 if (mread(bp->address, &bp->instr[0], 4) != 4) {
687 printf("Couldn't read instruction at %lx, "
688 "disabling breakpoint there\n", bp->address);
689 bp->enabled = 0;
690 continue;
691 }
692 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
693 printf("Breakpoint at %lx is on an mtmsrd or rfid "
694 "instruction, disabling it\n", bp->address);
695 bp->enabled = 0;
696 continue;
697 }
698 store_inst(&bp->instr[0]);
699 if (bp->enabled & BP_IABR)
700 continue;
701 if (mwrite(bp->address, &bpinstr, 4) != 4) {
702 printf("Couldn't write instruction at %lx, "
703 "disabling breakpoint there\n", bp->address);
704 bp->enabled &= ~BP_TRAP;
705 continue;
706 }
707 store_inst((void *)bp->address);
708 }
709}
710
711static void insert_cpu_bpts(void)
712{
713 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000714 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000716 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
718}
719
720static void remove_bpts(void)
721{
722 int i;
723 struct bpt *bp;
724 unsigned instr;
725
726 bp = bpts;
727 for (i = 0; i < NBPTS; ++i, ++bp) {
728 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
729 continue;
730 if (mread(bp->address, &instr, 4) == 4
731 && instr == bpinstr
732 && mwrite(bp->address, &bp->instr, 4) != 4)
733 printf("Couldn't remove breakpoint at %lx\n",
734 bp->address);
735 else
736 store_inst((void *)bp->address);
737 }
738}
739
740static void remove_cpu_bpts(void)
741{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000742 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000744 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
747/* Command interpreting routine */
748static char *last_cmd;
749
750static int
751cmds(struct pt_regs *excp)
752{
753 int cmd = 0;
754
755 last_cmd = NULL;
756 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200757
758 if (!xmon_no_auto_backtrace) {
759 xmon_no_auto_backtrace = 1;
760 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
761 }
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 for(;;) {
764#ifdef CONFIG_SMP
765 printf("%x:", smp_processor_id());
766#endif /* CONFIG_SMP */
767 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 flush_input();
769 termch = 0;
770 cmd = skipbl();
771 if( cmd == '\n' ) {
772 if (last_cmd == NULL)
773 continue;
774 take_input(last_cmd);
775 last_cmd = NULL;
776 cmd = inchar();
777 }
778 switch (cmd) {
779 case 'm':
780 cmd = inchar();
781 switch (cmd) {
782 case 'm':
783 case 's':
784 case 'd':
785 memops(cmd);
786 break;
787 case 'l':
788 memlocate();
789 break;
790 case 'z':
791 memzcan();
792 break;
793 case 'i':
794 show_mem();
795 break;
796 default:
797 termch = cmd;
798 memex();
799 }
800 break;
801 case 'd':
802 dump();
803 break;
804 case 'l':
805 symbol_lookup();
806 break;
807 case 'r':
808 prregs(excp); /* print regs */
809 break;
810 case 'e':
811 excprint(excp);
812 break;
813 case 'S':
814 super_regs();
815 break;
816 case 't':
817 backtrace(excp);
818 break;
819 case 'f':
820 cacheflush();
821 break;
822 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200823 if (do_spu_cmd() == 0)
824 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 if (do_step(excp))
826 return cmd;
827 break;
828 case 'x':
829 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100830 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100832 printf(" <no input ...>\n");
833 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 return cmd;
835 case '?':
836 printf(help_string);
837 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 case 'b':
839 bpt_cmds();
840 break;
841 case 'C':
842 csum();
843 break;
844 case 'c':
845 if (cpu_cmd())
846 return 0;
847 break;
848 case 'z':
849 bootcmds();
850 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000851 case 'p':
852 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000854#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 case 'u':
856 dump_segments();
857 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000858#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 default:
860 printf("Unrecognized command: ");
861 do {
862 if (' ' < cmd && cmd <= '~')
863 putchar(cmd);
864 else
865 printf("\\x%x", cmd);
866 cmd = inchar();
867 } while (cmd != '\n');
868 printf(" (type ? for help)\n");
869 break;
870 }
871 }
872}
873
874/*
875 * Step a single instruction.
876 * Some instructions we emulate, others we execute with MSR_SE set.
877 */
878static int do_step(struct pt_regs *regs)
879{
880 unsigned int instr;
881 int stepped;
882
883 /* check we are in 64-bit kernel mode, translation enabled */
884 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
885 if (mread(regs->nip, &instr, 4) == 4) {
886 stepped = emulate_step(regs, instr);
887 if (stepped < 0) {
888 printf("Couldn't single-step %s instruction\n",
889 (IS_RFID(instr)? "rfid": "mtmsrd"));
890 return 0;
891 }
892 if (stepped > 0) {
893 regs->trap = 0xd00 | (regs->trap & 1);
894 printf("stepped to ");
895 xmon_print_symbol(regs->nip, " ", "\n");
896 ppc_inst_dump(regs->nip, 1, 0);
897 return 0;
898 }
899 }
900 }
901 regs->msr |= MSR_SE;
902 return 1;
903}
904
905static void bootcmds(void)
906{
907 int cmd;
908
909 cmd = inchar();
910 if (cmd == 'r')
911 ppc_md.restart(NULL);
912 else if (cmd == 'h')
913 ppc_md.halt();
914 else if (cmd == 'p')
915 ppc_md.power_off();
916}
917
918static int cpu_cmd(void)
919{
920#ifdef CONFIG_SMP
921 unsigned long cpu;
922 int timeout;
923 int count;
924
925 if (!scanhex(&cpu)) {
926 /* print cpus waiting or in xmon */
927 printf("cpus stopped:");
928 count = 0;
929 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
930 if (cpu_isset(cpu, cpus_in_xmon)) {
931 if (count == 0)
932 printf(" %x", cpu);
933 ++count;
934 } else {
935 if (count > 1)
936 printf("-%x", cpu - 1);
937 count = 0;
938 }
939 }
940 if (count > 1)
941 printf("-%x", NR_CPUS - 1);
942 printf("\n");
943 return 0;
944 }
945 /* try to switch to cpu specified */
946 if (!cpu_isset(cpu, cpus_in_xmon)) {
947 printf("cpu 0x%x isn't in xmon\n", cpu);
948 return 0;
949 }
950 xmon_taken = 0;
951 mb();
952 xmon_owner = cpu;
953 timeout = 10000000;
954 while (!xmon_taken) {
955 if (--timeout == 0) {
956 if (test_and_set_bit(0, &xmon_taken))
957 break;
958 /* take control back */
959 mb();
960 xmon_owner = smp_processor_id();
961 printf("cpu %u didn't take control\n", cpu);
962 return 0;
963 }
964 barrier();
965 }
966 return 1;
967#else
968 return 0;
969#endif /* CONFIG_SMP */
970}
971
972static unsigned short fcstab[256] = {
973 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
974 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
975 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
976 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
977 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
978 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
979 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
980 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
981 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
982 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
983 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
984 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
985 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
986 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
987 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
988 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
989 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
990 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
991 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
992 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
993 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
994 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
995 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
996 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
997 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
998 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
999 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1000 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1001 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1002 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1003 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1004 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1005};
1006
1007#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1008
1009static void
1010csum(void)
1011{
1012 unsigned int i;
1013 unsigned short fcs;
1014 unsigned char v;
1015
1016 if (!scanhex(&adrs))
1017 return;
1018 if (!scanhex(&ncsum))
1019 return;
1020 fcs = 0xffff;
1021 for (i = 0; i < ncsum; ++i) {
1022 if (mread(adrs+i, &v, 1) == 0) {
1023 printf("csum stopped at %x\n", adrs+i);
1024 break;
1025 }
1026 fcs = FCS(fcs, v);
1027 }
1028 printf("%x\n", fcs);
1029}
1030
1031/*
1032 * Check if this is a suitable place to put a breakpoint.
1033 */
1034static long check_bp_loc(unsigned long addr)
1035{
1036 unsigned int instr;
1037
1038 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001039 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 printf("Breakpoints may only be placed at kernel addresses\n");
1041 return 0;
1042 }
1043 if (!mread(addr, &instr, sizeof(instr))) {
1044 printf("Can't read instruction at address %lx\n", addr);
1045 return 0;
1046 }
1047 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1048 printf("Breakpoints may not be placed on mtmsrd or rfid "
1049 "instructions\n");
1050 return 0;
1051 }
1052 return 1;
1053}
1054
1055static char *breakpoint_help_string =
1056 "Breakpoint command usage:\n"
1057 "b show breakpoints\n"
1058 "b <addr> [cnt] set breakpoint at given instr addr\n"
1059 "bc clear all breakpoints\n"
1060 "bc <n/addr> clear breakpoint number n or at addr\n"
1061 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1062 "bd <addr> [cnt] set hardware data breakpoint\n"
1063 "";
1064
1065static void
1066bpt_cmds(void)
1067{
1068 int cmd;
1069 unsigned long a;
1070 int mode, i;
1071 struct bpt *bp;
1072 const char badaddr[] = "Only kernel addresses are permitted "
1073 "for breakpoints\n";
1074
1075 cmd = inchar();
1076 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001077#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 case 'd': /* bd - hardware data breakpoint */
1079 mode = 7;
1080 cmd = inchar();
1081 if (cmd == 'r')
1082 mode = 5;
1083 else if (cmd == 'w')
1084 mode = 6;
1085 else
1086 termch = cmd;
1087 dabr.address = 0;
1088 dabr.enabled = 0;
1089 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001090 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 printf(badaddr);
1092 break;
1093 }
1094 dabr.address &= ~7;
1095 dabr.enabled = mode | BP_DABR;
1096 }
1097 break;
1098
1099 case 'i': /* bi - hardware instr breakpoint */
1100 if (!cpu_has_feature(CPU_FTR_IABR)) {
1101 printf("Hardware instruction breakpoint "
1102 "not supported on this cpu\n");
1103 break;
1104 }
1105 if (iabr) {
1106 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1107 iabr = NULL;
1108 }
1109 if (!scanhex(&a))
1110 break;
1111 if (!check_bp_loc(a))
1112 break;
1113 bp = new_breakpoint(a);
1114 if (bp != NULL) {
1115 bp->enabled |= BP_IABR | BP_IABR_TE;
1116 iabr = bp;
1117 }
1118 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001119#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
1121 case 'c':
1122 if (!scanhex(&a)) {
1123 /* clear all breakpoints */
1124 for (i = 0; i < NBPTS; ++i)
1125 bpts[i].enabled = 0;
1126 iabr = NULL;
1127 dabr.enabled = 0;
1128 printf("All breakpoints cleared\n");
1129 break;
1130 }
1131
1132 if (a <= NBPTS && a >= 1) {
1133 /* assume a breakpoint number */
1134 bp = &bpts[a-1]; /* bp nums are 1 based */
1135 } else {
1136 /* assume a breakpoint address */
1137 bp = at_breakpoint(a);
1138 if (bp == 0) {
1139 printf("No breakpoint at %x\n", a);
1140 break;
1141 }
1142 }
1143
1144 printf("Cleared breakpoint %x (", BP_NUM(bp));
1145 xmon_print_symbol(bp->address, " ", ")\n");
1146 bp->enabled = 0;
1147 break;
1148
1149 default:
1150 termch = cmd;
1151 cmd = skipbl();
1152 if (cmd == '?') {
1153 printf(breakpoint_help_string);
1154 break;
1155 }
1156 termch = cmd;
1157 if (!scanhex(&a)) {
1158 /* print all breakpoints */
1159 printf(" type address\n");
1160 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001161 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 if (dabr.enabled & 1)
1163 printf("r");
1164 if (dabr.enabled & 2)
1165 printf("w");
1166 printf("]\n");
1167 }
1168 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1169 if (!bp->enabled)
1170 continue;
1171 printf("%2x %s ", BP_NUM(bp),
1172 (bp->enabled & BP_IABR)? "inst": "trap");
1173 xmon_print_symbol(bp->address, " ", "\n");
1174 }
1175 break;
1176 }
1177
1178 if (!check_bp_loc(a))
1179 break;
1180 bp = new_breakpoint(a);
1181 if (bp != NULL)
1182 bp->enabled |= BP_TRAP;
1183 break;
1184 }
1185}
1186
1187/* Very cheap human name for vector lookup. */
1188static
1189const char *getvecname(unsigned long vec)
1190{
1191 char *ret;
1192
1193 switch (vec) {
1194 case 0x100: ret = "(System Reset)"; break;
1195 case 0x200: ret = "(Machine Check)"; break;
1196 case 0x300: ret = "(Data Access)"; break;
1197 case 0x380: ret = "(Data SLB Access)"; break;
1198 case 0x400: ret = "(Instruction Access)"; break;
1199 case 0x480: ret = "(Instruction SLB Access)"; break;
1200 case 0x500: ret = "(Hardware Interrupt)"; break;
1201 case 0x600: ret = "(Alignment)"; break;
1202 case 0x700: ret = "(Program Check)"; break;
1203 case 0x800: ret = "(FPU Unavailable)"; break;
1204 case 0x900: ret = "(Decrementer)"; break;
1205 case 0xc00: ret = "(System Call)"; break;
1206 case 0xd00: ret = "(Single Step)"; break;
1207 case 0xf00: ret = "(Performance Monitor)"; break;
1208 case 0xf20: ret = "(Altivec Unavailable)"; break;
1209 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1210 default: ret = "";
1211 }
1212 return ret;
1213}
1214
1215static void get_function_bounds(unsigned long pc, unsigned long *startp,
1216 unsigned long *endp)
1217{
1218 unsigned long size, offset;
1219 const char *name;
1220 char *modname;
1221
1222 *startp = *endp = 0;
1223 if (pc == 0)
1224 return;
1225 if (setjmp(bus_error_jmp) == 0) {
1226 catch_memory_errors = 1;
1227 sync();
1228 name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
1229 if (name != NULL) {
1230 *startp = pc - offset;
1231 *endp = pc - offset + size;
1232 }
1233 sync();
1234 }
1235 catch_memory_errors = 0;
1236}
1237
1238static int xmon_depth_to_print = 64;
1239
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001240#ifdef CONFIG_PPC64
1241#define LRSAVE_OFFSET 0x10
1242#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1243#define MARKER_OFFSET 0x60
1244#define REGS_OFFSET 0x70
1245#else
1246#define LRSAVE_OFFSET 4
1247#define REG_FRAME_MARKER 0x72656773
1248#define MARKER_OFFSET 8
1249#define REGS_OFFSET 16
1250#endif
1251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252static void xmon_show_stack(unsigned long sp, unsigned long lr,
1253 unsigned long pc)
1254{
1255 unsigned long ip;
1256 unsigned long newsp;
1257 unsigned long marker;
1258 int count = 0;
1259 struct pt_regs regs;
1260
1261 do {
1262 if (sp < PAGE_OFFSET) {
1263 if (sp != 0)
1264 printf("SP (%lx) is in userspace\n", sp);
1265 break;
1266 }
1267
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001268 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 || !mread(sp, &newsp, sizeof(unsigned long))) {
1270 printf("Couldn't read stack frame at %lx\n", sp);
1271 break;
1272 }
1273
1274 /*
1275 * For the first stack frame, try to work out if
1276 * LR and/or the saved LR value in the bottommost
1277 * stack frame are valid.
1278 */
1279 if ((pc | lr) != 0) {
1280 unsigned long fnstart, fnend;
1281 unsigned long nextip;
1282 int printip = 1;
1283
1284 get_function_bounds(pc, &fnstart, &fnend);
1285 nextip = 0;
1286 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001287 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 sizeof(unsigned long));
1289 if (lr == ip) {
1290 if (lr < PAGE_OFFSET
1291 || (fnstart <= lr && lr < fnend))
1292 printip = 0;
1293 } else if (lr == nextip) {
1294 printip = 0;
1295 } else if (lr >= PAGE_OFFSET
1296 && !(fnstart <= lr && lr < fnend)) {
1297 printf("[link register ] ");
1298 xmon_print_symbol(lr, " ", "\n");
1299 }
1300 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001301 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 xmon_print_symbol(ip, " ", " (unreliable)\n");
1303 }
1304 pc = lr = 0;
1305
1306 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001307 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 xmon_print_symbol(ip, " ", "\n");
1309 }
1310
1311 /* Look for "regshere" marker to see if this is
1312 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001313 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1314 && marker == REG_FRAME_MARKER) {
1315 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 != sizeof(regs)) {
1317 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001318 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 break;
1320 }
1321 printf("--- Exception: %lx %s at ", regs.trap,
1322 getvecname(TRAP(&regs)));
1323 pc = regs.nip;
1324 lr = regs.link;
1325 xmon_print_symbol(pc, " ", "\n");
1326 }
1327
1328 if (newsp == 0)
1329 break;
1330
1331 sp = newsp;
1332 } while (count++ < xmon_depth_to_print);
1333}
1334
1335static void backtrace(struct pt_regs *excp)
1336{
1337 unsigned long sp;
1338
1339 if (scanhex(&sp))
1340 xmon_show_stack(sp, 0, 0);
1341 else
1342 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1343 scannl();
1344}
1345
1346static void print_bug_trap(struct pt_regs *regs)
1347{
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001348 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 unsigned long addr;
1350
1351 if (regs->msr & MSR_PR)
1352 return; /* not in kernel */
1353 addr = regs->nip; /* address of trap instruction */
1354 if (addr < PAGE_OFFSET)
1355 return;
1356 bug = find_bug(regs->nip);
1357 if (bug == NULL)
1358 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001359 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 return;
1361
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001362#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001363 printf("kernel BUG at %s:%u!\n",
1364 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001365#else
1366 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1367#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368}
1369
1370void excprint(struct pt_regs *fp)
1371{
1372 unsigned long trap;
1373
1374#ifdef CONFIG_SMP
1375 printf("cpu 0x%x: ", smp_processor_id());
1376#endif /* CONFIG_SMP */
1377
1378 trap = TRAP(fp);
1379 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1380 printf(" pc: ");
1381 xmon_print_symbol(fp->nip, ": ", "\n");
1382
1383 printf(" lr: ", fp->link);
1384 xmon_print_symbol(fp->link, ": ", "\n");
1385
1386 printf(" sp: %lx\n", fp->gpr[1]);
1387 printf(" msr: %lx\n", fp->msr);
1388
1389 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1390 printf(" dar: %lx\n", fp->dar);
1391 if (trap != 0x380)
1392 printf(" dsisr: %lx\n", fp->dsisr);
1393 }
1394
1395 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001396#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001398#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 if (current) {
1400 printf(" pid = %ld, comm = %s\n",
1401 current->pid, current->comm);
1402 }
1403
1404 if (trap == 0x700)
1405 print_bug_trap(fp);
1406}
1407
1408void prregs(struct pt_regs *fp)
1409{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001410 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 unsigned long base;
1412 struct pt_regs regs;
1413
1414 if (scanhex(&base)) {
1415 if (setjmp(bus_error_jmp) == 0) {
1416 catch_memory_errors = 1;
1417 sync();
1418 regs = *(struct pt_regs *)base;
1419 sync();
1420 __delay(200);
1421 } else {
1422 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001423 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 base);
1425 return;
1426 }
1427 catch_memory_errors = 0;
1428 fp = &regs;
1429 }
1430
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001431#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 if (FULL_REGS(fp)) {
1433 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001434 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1436 } else {
1437 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001438 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1440 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001441#else
1442 for (n = 0; n < 32; ++n) {
1443 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1444 (n & 3) == 3? "\n": " ");
1445 if (n == 12 && !FULL_REGS(fp)) {
1446 printf("\n");
1447 break;
1448 }
1449 }
1450#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 printf("pc = ");
1452 xmon_print_symbol(fp->nip, " ", "\n");
1453 printf("lr = ");
1454 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001455 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1456 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001458 trap = TRAP(fp);
1459 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1460 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461}
1462
1463void cacheflush(void)
1464{
1465 int cmd;
1466 unsigned long nflush;
1467
1468 cmd = inchar();
1469 if (cmd != 'i')
1470 termch = cmd;
1471 scanhex((void *)&adrs);
1472 if (termch != '\n')
1473 termch = 0;
1474 nflush = 1;
1475 scanhex(&nflush);
1476 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1477 if (setjmp(bus_error_jmp) == 0) {
1478 catch_memory_errors = 1;
1479 sync();
1480
1481 if (cmd != 'i') {
1482 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1483 cflush((void *) adrs);
1484 } else {
1485 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1486 cinval((void *) adrs);
1487 }
1488 sync();
1489 /* wait a little while to see if we get a machine check */
1490 __delay(200);
1491 }
1492 catch_memory_errors = 0;
1493}
1494
1495unsigned long
1496read_spr(int n)
1497{
1498 unsigned int instrs[2];
1499 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001501#ifdef CONFIG_PPC64
1502 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 opd[0] = (unsigned long)instrs;
1505 opd[1] = 0;
1506 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001507 code = (unsigned long (*)(void)) opd;
1508#else
1509 code = (unsigned long (*)(void)) instrs;
1510#endif
1511
1512 /* mfspr r3,n; blr */
1513 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1514 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 store_inst(instrs);
1516 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
1518 if (setjmp(bus_error_jmp) == 0) {
1519 catch_memory_errors = 1;
1520 sync();
1521
1522 ret = code();
1523
1524 sync();
1525 /* wait a little while to see if we get a machine check */
1526 __delay(200);
1527 n = size;
1528 }
1529
1530 return ret;
1531}
1532
1533void
1534write_spr(int n, unsigned long val)
1535{
1536 unsigned int instrs[2];
1537 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001538#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 unsigned long opd[3];
1540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 opd[0] = (unsigned long)instrs;
1542 opd[1] = 0;
1543 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001544 code = (unsigned long (*)(unsigned long)) opd;
1545#else
1546 code = (unsigned long (*)(unsigned long)) instrs;
1547#endif
1548
1549 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1550 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 store_inst(instrs);
1552 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
1554 if (setjmp(bus_error_jmp) == 0) {
1555 catch_memory_errors = 1;
1556 sync();
1557
1558 code(val);
1559
1560 sync();
1561 /* wait a little while to see if we get a machine check */
1562 __delay(200);
1563 n = size;
1564 }
1565}
1566
1567static unsigned long regno;
1568extern char exc_prolog;
1569extern char dec_exc;
1570
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001571void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572{
1573 int cmd;
1574 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576 cmd = skipbl();
1577 if (cmd == '\n') {
1578 unsigned long sp, toc;
1579 asm("mr %0,1" : "=r" (sp) :);
1580 asm("mr %0,2" : "=r" (toc) :);
1581
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001582 printf("msr = "REG" sprg0= "REG"\n",
1583 mfmsr(), mfspr(SPRN_SPRG0));
1584 printf("pvr = "REG" sprg1= "REG"\n",
1585 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1586 printf("dec = "REG" sprg2= "REG"\n",
1587 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1588 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1589 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590#ifdef CONFIG_PPC_ISERIES
Stephen Rothwell1d135812006-11-13 14:50:28 +11001591 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1592 struct paca_struct *ptrPaca;
1593 struct lppaca *ptrLpPaca;
1594 struct ItLpRegSave *ptrLpRegSave;
1595
1596 /* Dump out relevant Paca data areas. */
1597 printf("Paca: \n");
1598 ptrPaca = get_paca();
1599
1600 printf(" Local Processor Control Area (LpPaca): \n");
1601 ptrLpPaca = ptrPaca->lppaca_ptr;
1602 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1603 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1604 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1605 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1606 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1607
1608 printf(" Local Processor Register Save Area (LpRegSave): \n");
1609 ptrLpRegSave = ptrPaca->reg_save_ptr;
1610 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1611 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1612 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1613 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1614 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1615 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617#endif
1618
1619 return;
1620 }
1621
1622 scanhex(&regno);
1623 switch (cmd) {
1624 case 'w':
1625 val = read_spr(regno);
1626 scanhex(&val);
1627 write_spr(regno, val);
1628 /* fall through */
1629 case 'r':
1630 printf("spr %lx = %lx\n", regno, read_spr(regno));
1631 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 }
1633 scannl();
1634}
1635
1636/*
1637 * Stuff for reading and writing memory safely
1638 */
1639int
1640mread(unsigned long adrs, void *buf, int size)
1641{
1642 volatile int n;
1643 char *p, *q;
1644
1645 n = 0;
1646 if (setjmp(bus_error_jmp) == 0) {
1647 catch_memory_errors = 1;
1648 sync();
1649 p = (char *)adrs;
1650 q = (char *)buf;
1651 switch (size) {
1652 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001653 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 break;
1655 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001656 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 break;
1658 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001659 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 break;
1661 default:
1662 for( ; n < size; ++n) {
1663 *q++ = *p++;
1664 sync();
1665 }
1666 }
1667 sync();
1668 /* wait a little while to see if we get a machine check */
1669 __delay(200);
1670 n = size;
1671 }
1672 catch_memory_errors = 0;
1673 return n;
1674}
1675
1676int
1677mwrite(unsigned long adrs, void *buf, int size)
1678{
1679 volatile int n;
1680 char *p, *q;
1681
1682 n = 0;
1683 if (setjmp(bus_error_jmp) == 0) {
1684 catch_memory_errors = 1;
1685 sync();
1686 p = (char *) adrs;
1687 q = (char *) buf;
1688 switch (size) {
1689 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001690 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 break;
1692 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001693 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 break;
1695 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001696 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 break;
1698 default:
1699 for ( ; n < size; ++n) {
1700 *p++ = *q++;
1701 sync();
1702 }
1703 }
1704 sync();
1705 /* wait a little while to see if we get a machine check */
1706 __delay(200);
1707 n = size;
1708 } else {
1709 printf("*** Error writing address %x\n", adrs + n);
1710 }
1711 catch_memory_errors = 0;
1712 return n;
1713}
1714
1715static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001716static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717static char *fault_chars[] = { "--", "**", "##" };
1718
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001719static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001721 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 switch (TRAP(regs)) {
1723 case 0x200:
1724 fault_type = 0;
1725 break;
1726 case 0x300:
1727 case 0x380:
1728 fault_type = 1;
1729 break;
1730 default:
1731 fault_type = 2;
1732 }
1733
1734 longjmp(bus_error_jmp, 1);
1735
1736 return 0;
1737}
1738
1739#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1740
1741void
1742byterev(unsigned char *val, int size)
1743{
1744 int t;
1745
1746 switch (size) {
1747 case 2:
1748 SWAP(val[0], val[1], t);
1749 break;
1750 case 4:
1751 SWAP(val[0], val[3], t);
1752 SWAP(val[1], val[2], t);
1753 break;
1754 case 8: /* is there really any use for this? */
1755 SWAP(val[0], val[7], t);
1756 SWAP(val[1], val[6], t);
1757 SWAP(val[2], val[5], t);
1758 SWAP(val[3], val[4], t);
1759 break;
1760 }
1761}
1762
1763static int brev;
1764static int mnoread;
1765
1766static char *memex_help_string =
1767 "Memory examine command usage:\n"
1768 "m [addr] [flags] examine/change memory\n"
1769 " addr is optional. will start where left off.\n"
1770 " flags may include chars from this set:\n"
1771 " b modify by bytes (default)\n"
1772 " w modify by words (2 byte)\n"
1773 " l modify by longs (4 byte)\n"
1774 " d modify by doubleword (8 byte)\n"
1775 " r toggle reverse byte order mode\n"
1776 " n do not read memory (for i/o spaces)\n"
1777 " . ok to read (default)\n"
1778 "NOTE: flags are saved as defaults\n"
1779 "";
1780
1781static char *memex_subcmd_help_string =
1782 "Memory examine subcommands:\n"
1783 " hexval write this val to current location\n"
1784 " 'string' write chars from string to this location\n"
1785 " ' increment address\n"
1786 " ^ decrement address\n"
1787 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1788 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1789 " ` clear no-read flag\n"
1790 " ; stay at this addr\n"
1791 " v change to byte mode\n"
1792 " w change to word (2 byte) mode\n"
1793 " l change to long (4 byte) mode\n"
1794 " u change to doubleword (8 byte) mode\n"
1795 " m addr change current addr\n"
1796 " n toggle no-read flag\n"
1797 " r toggle byte reverse flag\n"
1798 " < count back up count bytes\n"
1799 " > count skip forward count bytes\n"
1800 " x exit this mode\n"
1801 "";
1802
1803void
1804memex(void)
1805{
1806 int cmd, inc, i, nslash;
1807 unsigned long n;
1808 unsigned char val[16];
1809
1810 scanhex((void *)&adrs);
1811 cmd = skipbl();
1812 if (cmd == '?') {
1813 printf(memex_help_string);
1814 return;
1815 } else {
1816 termch = cmd;
1817 }
1818 last_cmd = "m\n";
1819 while ((cmd = skipbl()) != '\n') {
1820 switch( cmd ){
1821 case 'b': size = 1; break;
1822 case 'w': size = 2; break;
1823 case 'l': size = 4; break;
1824 case 'd': size = 8; break;
1825 case 'r': brev = !brev; break;
1826 case 'n': mnoread = 1; break;
1827 case '.': mnoread = 0; break;
1828 }
1829 }
1830 if( size <= 0 )
1831 size = 1;
1832 else if( size > 8 )
1833 size = 8;
1834 for(;;){
1835 if (!mnoread)
1836 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001837 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 if (!mnoread) {
1839 if (brev)
1840 byterev(val, size);
1841 putchar(' ');
1842 for (i = 0; i < n; ++i)
1843 printf("%.2x", val[i]);
1844 for (; i < size; ++i)
1845 printf("%s", fault_chars[fault_type]);
1846 }
1847 putchar(' ');
1848 inc = size;
1849 nslash = 0;
1850 for(;;){
1851 if( scanhex(&n) ){
1852 for (i = 0; i < size; ++i)
1853 val[i] = n >> (i * 8);
1854 if (!brev)
1855 byterev(val, size);
1856 mwrite(adrs, val, size);
1857 inc = size;
1858 }
1859 cmd = skipbl();
1860 if (cmd == '\n')
1861 break;
1862 inc = 0;
1863 switch (cmd) {
1864 case '\'':
1865 for(;;){
1866 n = inchar();
1867 if( n == '\\' )
1868 n = bsesc();
1869 else if( n == '\'' )
1870 break;
1871 for (i = 0; i < size; ++i)
1872 val[i] = n >> (i * 8);
1873 if (!brev)
1874 byterev(val, size);
1875 mwrite(adrs, val, size);
1876 adrs += size;
1877 }
1878 adrs -= size;
1879 inc = size;
1880 break;
1881 case ',':
1882 adrs += size;
1883 break;
1884 case '.':
1885 mnoread = 0;
1886 break;
1887 case ';':
1888 break;
1889 case 'x':
1890 case EOF:
1891 scannl();
1892 return;
1893 case 'b':
1894 case 'v':
1895 size = 1;
1896 break;
1897 case 'w':
1898 size = 2;
1899 break;
1900 case 'l':
1901 size = 4;
1902 break;
1903 case 'u':
1904 size = 8;
1905 break;
1906 case '^':
1907 adrs -= size;
1908 break;
1909 break;
1910 case '/':
1911 if (nslash > 0)
1912 adrs -= 1 << nslash;
1913 else
1914 nslash = 0;
1915 nslash += 4;
1916 adrs += 1 << nslash;
1917 break;
1918 case '\\':
1919 if (nslash < 0)
1920 adrs += 1 << -nslash;
1921 else
1922 nslash = 0;
1923 nslash -= 4;
1924 adrs -= 1 << -nslash;
1925 break;
1926 case 'm':
1927 scanhex((void *)&adrs);
1928 break;
1929 case 'n':
1930 mnoread = 1;
1931 break;
1932 case 'r':
1933 brev = !brev;
1934 break;
1935 case '<':
1936 n = size;
1937 scanhex(&n);
1938 adrs -= n;
1939 break;
1940 case '>':
1941 n = size;
1942 scanhex(&n);
1943 adrs += n;
1944 break;
1945 case '?':
1946 printf(memex_subcmd_help_string);
1947 break;
1948 }
1949 }
1950 adrs += inc;
1951 }
1952}
1953
1954int
1955bsesc(void)
1956{
1957 int c;
1958
1959 c = inchar();
1960 switch( c ){
1961 case 'n': c = '\n'; break;
1962 case 'r': c = '\r'; break;
1963 case 'b': c = '\b'; break;
1964 case 't': c = '\t'; break;
1965 }
1966 return c;
1967}
1968
Olaf Hering7e5b5932006-03-08 20:40:28 +01001969static void xmon_rawdump (unsigned long adrs, long ndump)
1970{
1971 long n, m, r, nr;
1972 unsigned char temp[16];
1973
1974 for (n = ndump; n > 0;) {
1975 r = n < 16? n: 16;
1976 nr = mread(adrs, temp, r);
1977 adrs += nr;
1978 for (m = 0; m < r; ++m) {
1979 if (m < nr)
1980 printf("%.2x", temp[m]);
1981 else
1982 printf("%s", fault_chars[fault_type]);
1983 }
1984 n -= r;
1985 if (nr < r)
1986 break;
1987 }
1988 printf("\n");
1989}
1990
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
1992 || ('a' <= (c) && (c) <= 'f') \
1993 || ('A' <= (c) && (c) <= 'F'))
1994void
1995dump(void)
1996{
1997 int c;
1998
1999 c = inchar();
2000 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2001 termch = c;
2002 scanhex((void *)&adrs);
2003 if (termch != '\n')
2004 termch = 0;
2005 if (c == 'i') {
2006 scanhex(&nidump);
2007 if (nidump == 0)
2008 nidump = 16;
2009 else if (nidump > MAX_DUMP)
2010 nidump = MAX_DUMP;
2011 adrs += ppc_inst_dump(adrs, nidump, 1);
2012 last_cmd = "di\n";
Olaf Hering7e5b5932006-03-08 20:40:28 +01002013 } else if (c == 'r') {
2014 scanhex(&ndump);
2015 if (ndump == 0)
2016 ndump = 64;
2017 xmon_rawdump(adrs, ndump);
2018 adrs += ndump;
2019 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 } else {
2021 scanhex(&ndump);
2022 if (ndump == 0)
2023 ndump = 64;
2024 else if (ndump > MAX_DUMP)
2025 ndump = MAX_DUMP;
2026 prdump(adrs, ndump);
2027 adrs += ndump;
2028 last_cmd = "d\n";
2029 }
2030}
2031
2032void
2033prdump(unsigned long adrs, long ndump)
2034{
2035 long n, m, c, r, nr;
2036 unsigned char temp[16];
2037
2038 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002039 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 putchar(' ');
2041 r = n < 16? n: 16;
2042 nr = mread(adrs, temp, r);
2043 adrs += nr;
2044 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002045 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2046 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 if (m < nr)
2048 printf("%.2x", temp[m]);
2049 else
2050 printf("%s", fault_chars[fault_type]);
2051 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002052 for (; m < 16; ++m) {
2053 if ((m & (sizeof(long) - 1)) == 0)
2054 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 printf(" |");
2058 for (m = 0; m < r; ++m) {
2059 if (m < nr) {
2060 c = temp[m];
2061 putchar(' ' <= c && c <= '~'? c: '.');
2062 } else
2063 putchar(' ');
2064 }
2065 n -= r;
2066 for (; m < 16; ++m)
2067 putchar(' ');
2068 printf("|\n");
2069 if (nr < r)
2070 break;
2071 }
2072}
2073
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002074typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2075
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002077generic_inst_dump(unsigned long adr, long count, int praddr,
2078 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079{
2080 int nr, dotted;
2081 unsigned long first_adr;
2082 unsigned long inst, last_inst = 0;
2083 unsigned char val[4];
2084
2085 dotted = 0;
2086 for (first_adr = adr; count > 0; --count, adr += 4) {
2087 nr = mread(adr, val, 4);
2088 if (nr == 0) {
2089 if (praddr) {
2090 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002091 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 }
2093 break;
2094 }
2095 inst = GETWORD(val);
2096 if (adr > first_adr && inst == last_inst) {
2097 if (!dotted) {
2098 printf(" ...\n");
2099 dotted = 1;
2100 }
2101 continue;
2102 }
2103 dotted = 0;
2104 last_inst = inst;
2105 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002106 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002108 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 printf("\n");
2110 }
2111 return adr - first_adr;
2112}
2113
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002114int
2115ppc_inst_dump(unsigned long adr, long count, int praddr)
2116{
2117 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2118}
2119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120void
2121print_address(unsigned long addr)
2122{
2123 xmon_print_symbol(addr, "\t# ", "");
2124}
2125
2126
2127/*
2128 * Memory operations - move, set, print differences
2129 */
2130static unsigned long mdest; /* destination address */
2131static unsigned long msrc; /* source address */
2132static unsigned long mval; /* byte value to set memory to */
2133static unsigned long mcount; /* # bytes to affect */
2134static unsigned long mdiffs; /* max # differences to print */
2135
2136void
2137memops(int cmd)
2138{
2139 scanhex((void *)&mdest);
2140 if( termch != '\n' )
2141 termch = 0;
2142 scanhex((void *)(cmd == 's'? &mval: &msrc));
2143 if( termch != '\n' )
2144 termch = 0;
2145 scanhex((void *)&mcount);
2146 switch( cmd ){
2147 case 'm':
2148 memmove((void *)mdest, (void *)msrc, mcount);
2149 break;
2150 case 's':
2151 memset((void *)mdest, mval, mcount);
2152 break;
2153 case 'd':
2154 if( termch != '\n' )
2155 termch = 0;
2156 scanhex((void *)&mdiffs);
2157 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2158 break;
2159 }
2160}
2161
2162void
2163memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2164{
2165 unsigned n, prt;
2166
2167 prt = 0;
2168 for( n = nb; n > 0; --n )
2169 if( *p1++ != *p2++ )
2170 if( ++prt <= maxpr )
2171 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2172 p1[-1], p2 - 1, p2[-1]);
2173 if( prt > maxpr )
2174 printf("Total of %d differences\n", prt);
2175}
2176
2177static unsigned mend;
2178static unsigned mask;
2179
2180void
2181memlocate(void)
2182{
2183 unsigned a, n;
2184 unsigned char val[4];
2185
2186 last_cmd = "ml";
2187 scanhex((void *)&mdest);
2188 if (termch != '\n') {
2189 termch = 0;
2190 scanhex((void *)&mend);
2191 if (termch != '\n') {
2192 termch = 0;
2193 scanhex((void *)&mval);
2194 mask = ~0;
2195 if (termch != '\n') termch = 0;
2196 scanhex((void *)&mask);
2197 }
2198 }
2199 n = 0;
2200 for (a = mdest; a < mend; a += 4) {
2201 if (mread(a, val, 4) == 4
2202 && ((GETWORD(val) ^ mval) & mask) == 0) {
2203 printf("%.16x: %.16x\n", a, GETWORD(val));
2204 if (++n >= 10)
2205 break;
2206 }
2207 }
2208}
2209
2210static unsigned long mskip = 0x1000;
2211static unsigned long mlim = 0xffffffff;
2212
2213void
2214memzcan(void)
2215{
2216 unsigned char v;
2217 unsigned a;
2218 int ok, ook;
2219
2220 scanhex(&mdest);
2221 if (termch != '\n') termch = 0;
2222 scanhex(&mskip);
2223 if (termch != '\n') termch = 0;
2224 scanhex(&mlim);
2225 ook = 0;
2226 for (a = mdest; a < mlim; a += mskip) {
2227 ok = mread(a, &v, 1);
2228 if (ok && !ook) {
2229 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 } else if (!ok && ook)
2231 printf("%.8x\n", a - mskip);
2232 ook = ok;
2233 if (a + mskip < a)
2234 break;
2235 }
2236 if (ook)
2237 printf("%.8x\n", a - mskip);
2238}
2239
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002240void proccall(void)
2241{
2242 unsigned long args[8];
2243 unsigned long ret;
2244 int i;
2245 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2246 unsigned long, unsigned long, unsigned long,
2247 unsigned long, unsigned long, unsigned long);
2248 callfunc_t func;
2249
2250 if (!scanhex(&adrs))
2251 return;
2252 if (termch != '\n')
2253 termch = 0;
2254 for (i = 0; i < 8; ++i)
2255 args[i] = 0;
2256 for (i = 0; i < 8; ++i) {
2257 if (!scanhex(&args[i]) || termch == '\n')
2258 break;
2259 termch = 0;
2260 }
2261 func = (callfunc_t) adrs;
2262 ret = 0;
2263 if (setjmp(bus_error_jmp) == 0) {
2264 catch_memory_errors = 1;
2265 sync();
2266 ret = func(args[0], args[1], args[2], args[3],
2267 args[4], args[5], args[6], args[7]);
2268 sync();
2269 printf("return value is %x\n", ret);
2270 } else {
2271 printf("*** %x exception occurred\n", fault_except);
2272 }
2273 catch_memory_errors = 0;
2274}
2275
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276/* Input scanning routines */
2277int
2278skipbl(void)
2279{
2280 int c;
2281
2282 if( termch != 0 ){
2283 c = termch;
2284 termch = 0;
2285 } else
2286 c = inchar();
2287 while( c == ' ' || c == '\t' )
2288 c = inchar();
2289 return c;
2290}
2291
2292#define N_PTREGS 44
2293static char *regnames[N_PTREGS] = {
2294 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2295 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2296 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2297 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002298 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2299#ifdef CONFIG_PPC64
2300 "softe",
2301#else
2302 "mq",
2303#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 "trap", "dar", "dsisr", "res"
2305};
2306
2307int
2308scanhex(unsigned long *vp)
2309{
2310 int c, d;
2311 unsigned long v;
2312
2313 c = skipbl();
2314 if (c == '%') {
2315 /* parse register name */
2316 char regname[8];
2317 int i;
2318
2319 for (i = 0; i < sizeof(regname) - 1; ++i) {
2320 c = inchar();
2321 if (!isalnum(c)) {
2322 termch = c;
2323 break;
2324 }
2325 regname[i] = c;
2326 }
2327 regname[i] = 0;
2328 for (i = 0; i < N_PTREGS; ++i) {
2329 if (strcmp(regnames[i], regname) == 0) {
2330 if (xmon_regs == NULL) {
2331 printf("regs not available\n");
2332 return 0;
2333 }
2334 *vp = ((unsigned long *)xmon_regs)[i];
2335 return 1;
2336 }
2337 }
2338 printf("invalid register name '%%%s'\n", regname);
2339 return 0;
2340 }
2341
2342 /* skip leading "0x" if any */
2343
2344 if (c == '0') {
2345 c = inchar();
2346 if (c == 'x') {
2347 c = inchar();
2348 } else {
2349 d = hexdigit(c);
2350 if (d == EOF) {
2351 termch = c;
2352 *vp = 0;
2353 return 1;
2354 }
2355 }
2356 } else if (c == '$') {
2357 int i;
2358 for (i=0; i<63; i++) {
2359 c = inchar();
2360 if (isspace(c)) {
2361 termch = c;
2362 break;
2363 }
2364 tmpstr[i] = c;
2365 }
2366 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002367 *vp = 0;
2368 if (setjmp(bus_error_jmp) == 0) {
2369 catch_memory_errors = 1;
2370 sync();
2371 *vp = kallsyms_lookup_name(tmpstr);
2372 sync();
2373 }
2374 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 if (!(*vp)) {
2376 printf("unknown symbol '%s'\n", tmpstr);
2377 return 0;
2378 }
2379 return 1;
2380 }
2381
2382 d = hexdigit(c);
2383 if (d == EOF) {
2384 termch = c;
2385 return 0;
2386 }
2387 v = 0;
2388 do {
2389 v = (v << 4) + d;
2390 c = inchar();
2391 d = hexdigit(c);
2392 } while (d != EOF);
2393 termch = c;
2394 *vp = v;
2395 return 1;
2396}
2397
2398void
2399scannl(void)
2400{
2401 int c;
2402
2403 c = termch;
2404 termch = 0;
2405 while( c != '\n' )
2406 c = inchar();
2407}
2408
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002409int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410{
2411 if( '0' <= c && c <= '9' )
2412 return c - '0';
2413 if( 'A' <= c && c <= 'F' )
2414 return c - ('A' - 10);
2415 if( 'a' <= c && c <= 'f' )
2416 return c - ('a' - 10);
2417 return EOF;
2418}
2419
2420void
2421getstring(char *s, int size)
2422{
2423 int c;
2424
2425 c = skipbl();
2426 do {
2427 if( size > 1 ){
2428 *s++ = c;
2429 --size;
2430 }
2431 c = inchar();
2432 } while( c != ' ' && c != '\t' && c != '\n' );
2433 termch = c;
2434 *s = 0;
2435}
2436
2437static char line[256];
2438static char *lineptr;
2439
2440void
2441flush_input(void)
2442{
2443 lineptr = NULL;
2444}
2445
2446int
2447inchar(void)
2448{
2449 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002450 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 lineptr = NULL;
2452 return EOF;
2453 }
2454 lineptr = line;
2455 }
2456 return *lineptr++;
2457}
2458
2459void
2460take_input(char *str)
2461{
2462 lineptr = str;
2463}
2464
2465
2466static void
2467symbol_lookup(void)
2468{
2469 int type = inchar();
2470 unsigned long addr;
2471 static char tmp[64];
2472
2473 switch (type) {
2474 case 'a':
2475 if (scanhex(&addr))
2476 xmon_print_symbol(addr, ": ", "\n");
2477 termch = 0;
2478 break;
2479 case 's':
2480 getstring(tmp, 64);
2481 if (setjmp(bus_error_jmp) == 0) {
2482 catch_memory_errors = 1;
2483 sync();
2484 addr = kallsyms_lookup_name(tmp);
2485 if (addr)
2486 printf("%s: %lx\n", tmp, addr);
2487 else
2488 printf("Symbol '%s' not found.\n", tmp);
2489 sync();
2490 }
2491 catch_memory_errors = 0;
2492 termch = 0;
2493 break;
2494 }
2495}
2496
2497
2498/* Print an address in numeric and symbolic form (if possible) */
2499static void xmon_print_symbol(unsigned long address, const char *mid,
2500 const char *after)
2501{
2502 char *modname;
2503 const char *name = NULL;
2504 unsigned long offset, size;
2505
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002506 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 if (setjmp(bus_error_jmp) == 0) {
2508 catch_memory_errors = 1;
2509 sync();
2510 name = kallsyms_lookup(address, &size, &offset, &modname,
2511 tmpstr);
2512 sync();
2513 /* wait a little while to see if we get a machine check */
2514 __delay(200);
2515 }
2516
2517 catch_memory_errors = 0;
2518
2519 if (name) {
2520 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2521 if (modname)
2522 printf(" [%s]", modname);
2523 }
2524 printf("%s", after);
2525}
2526
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002527#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528static void dump_slb(void)
2529{
2530 int i;
2531 unsigned long tmp;
2532
2533 printf("SLB contents of cpu %x\n", smp_processor_id());
2534
2535 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2536 asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
2537 printf("%02d %016lx ", i, tmp);
2538
2539 asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
2540 printf("%016lx\n", tmp);
2541 }
2542}
2543
2544static void dump_stab(void)
2545{
2546 int i;
2547 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2548
2549 printf("Segment table contents of cpu %x\n", smp_processor_id());
2550
2551 for (i = 0; i < PAGE_SIZE/16; i++) {
2552 unsigned long a, b;
2553
2554 a = *tmp++;
2555 b = *tmp++;
2556
2557 if (a || b) {
2558 printf("%03d %016lx ", i, a);
2559 printf("%016lx\n", b);
2560 }
2561 }
2562}
2563
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002564void dump_segments(void)
2565{
2566 if (cpu_has_feature(CPU_FTR_SLB))
2567 dump_slb();
2568 else
2569 dump_stab();
2570}
2571#endif
2572
2573#ifdef CONFIG_PPC_STD_MMU_32
2574void dump_segments(void)
2575{
2576 int i;
2577
2578 printf("sr0-15 =");
2579 for (i = 0; i < 16; ++i)
2580 printf(" %x", mfsrin(i));
2581 printf("\n");
2582}
2583#endif
2584
Olaf Heringb13cfd172005-08-04 19:26:42 +02002585void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002587#ifdef CONFIG_PPC_ISERIES
2588 if (firmware_has_feature(FW_FEATURE_ISERIES))
2589 return;
2590#endif
Olaf Heringb13cfd172005-08-04 19:26:42 +02002591 if (enable) {
2592 __debugger = xmon;
2593 __debugger_ipi = xmon_ipi;
2594 __debugger_bpt = xmon_bpt;
2595 __debugger_sstep = xmon_sstep;
2596 __debugger_iabr_match = xmon_iabr_match;
2597 __debugger_dabr_match = xmon_dabr_match;
2598 __debugger_fault_handler = xmon_fault_handler;
2599 } else {
2600 __debugger = NULL;
2601 __debugger_ipi = NULL;
2602 __debugger_bpt = NULL;
2603 __debugger_sstep = NULL;
2604 __debugger_iabr_match = NULL;
2605 __debugger_dabr_match = NULL;
2606 __debugger_fault_handler = NULL;
2607 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002608 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002610
2611#ifdef CONFIG_MAGIC_SYSRQ
David Howells7d12e782006-10-05 14:55:46 +01002612static void sysrq_handle_xmon(int key, struct tty_struct *tty)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002613{
2614 /* ensure xmon is enabled */
2615 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002616 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002617}
2618
2619static struct sysrq_key_op sysrq_xmon_op =
2620{
2621 .handler = sysrq_handle_xmon,
2622 .help_msg = "Xmon",
2623 .action_msg = "Entering xmon",
2624};
2625
2626static int __init setup_xmon_sysrq(void)
2627{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002628#ifdef CONFIG_PPC_ISERIES
2629 if (firmware_has_feature(FW_FEATURE_ISERIES))
2630 return 0;
2631#endif
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002632 register_sysrq_key('x', &sysrq_xmon_op);
2633 return 0;
2634}
2635__initcall(setup_xmon_sysrq);
2636#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002637
2638int __initdata xmon_early, xmon_off;
2639
2640static int __init early_parse_xmon(char *p)
2641{
2642 if (!p || strncmp(p, "early", 5) == 0) {
2643 /* just "xmon" is equivalent to "xmon=early" */
2644 xmon_init(1);
2645 xmon_early = 1;
2646 } else if (strncmp(p, "on", 2) == 0)
2647 xmon_init(1);
2648 else if (strncmp(p, "off", 3) == 0)
2649 xmon_off = 1;
2650 else if (strncmp(p, "nobt", 4) == 0)
2651 xmon_no_auto_backtrace = 1;
2652 else
2653 return 1;
2654
2655 return 0;
2656}
2657early_param("xmon", early_parse_xmon);
2658
2659void __init xmon_setup(void)
2660{
2661#ifdef CONFIG_XMON_DEFAULT
2662 if (!xmon_off)
2663 xmon_init(1);
2664#endif
2665 if (xmon_early)
2666 debugger(NULL);
2667}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002668
Arnd Bergmanne0555952006-11-27 19:18:55 +01002669#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002670
2671struct spu_info {
2672 struct spu *spu;
2673 u64 saved_mfc_sr1_RW;
2674 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002675 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002676 u8 stopped_ok;
2677};
2678
2679#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2680
2681static struct spu_info spu_info[XMON_NUM_SPUS];
2682
2683void xmon_register_spus(struct list_head *list)
2684{
2685 struct spu *spu;
2686
2687 list_for_each_entry(spu, list, full_list) {
2688 if (spu->number >= XMON_NUM_SPUS) {
2689 WARN_ON(1);
2690 continue;
2691 }
2692
2693 spu_info[spu->number].spu = spu;
2694 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002695 spu_info[spu->number].dump_addr = (unsigned long)
2696 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002697 }
2698}
2699
2700static void stop_spus(void)
2701{
2702 struct spu *spu;
2703 int i;
2704 u64 tmp;
2705
2706 for (i = 0; i < XMON_NUM_SPUS; i++) {
2707 if (!spu_info[i].spu)
2708 continue;
2709
2710 if (setjmp(bus_error_jmp) == 0) {
2711 catch_memory_errors = 1;
2712 sync();
2713
2714 spu = spu_info[i].spu;
2715
2716 spu_info[i].saved_spu_runcntl_RW =
2717 in_be32(&spu->problem->spu_runcntl_RW);
2718
2719 tmp = spu_mfc_sr1_get(spu);
2720 spu_info[i].saved_mfc_sr1_RW = tmp;
2721
2722 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2723 spu_mfc_sr1_set(spu, tmp);
2724
2725 sync();
2726 __delay(200);
2727
2728 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01002729
2730 printf("Stopped spu %.2d (was %s)\n", i,
2731 spu_info[i].saved_spu_runcntl_RW ?
2732 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002733 } else {
2734 catch_memory_errors = 0;
2735 printf("*** Error stopping spu %.2d\n", i);
2736 }
2737 catch_memory_errors = 0;
2738 }
2739}
2740
2741static void restart_spus(void)
2742{
2743 struct spu *spu;
2744 int i;
2745
2746 for (i = 0; i < XMON_NUM_SPUS; i++) {
2747 if (!spu_info[i].spu)
2748 continue;
2749
2750 if (!spu_info[i].stopped_ok) {
2751 printf("*** Error, spu %d was not successfully stopped"
2752 ", not restarting\n", i);
2753 continue;
2754 }
2755
2756 if (setjmp(bus_error_jmp) == 0) {
2757 catch_memory_errors = 1;
2758 sync();
2759
2760 spu = spu_info[i].spu;
2761 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2762 out_be32(&spu->problem->spu_runcntl_RW,
2763 spu_info[i].saved_spu_runcntl_RW);
2764
2765 sync();
2766 __delay(200);
2767
2768 printf("Restarted spu %.2d\n", i);
2769 } else {
2770 catch_memory_errors = 0;
2771 printf("*** Error restarting spu %.2d\n", i);
2772 }
2773 catch_memory_errors = 0;
2774 }
2775}
2776
Michael Ellermana8984972006-10-24 18:31:28 +02002777#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01002778#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02002779do { \
2780 if (setjmp(bus_error_jmp) == 0) { \
2781 catch_memory_errors = 1; \
2782 sync(); \
2783 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01002784 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02002785 sync(); \
2786 __delay(200); \
2787 } else { \
2788 catch_memory_errors = 0; \
2789 printf(" %-*s = *** Error reading field.\n", \
2790 DUMP_WIDTH, #field); \
2791 } \
2792 catch_memory_errors = 0; \
2793} while (0)
2794
Michael Ellerman437a0702006-11-23 00:46:39 +01002795#define DUMP_FIELD(obj, format, field) \
2796 DUMP_VALUE(format, field, obj->field)
2797
Michael Ellermana8984972006-10-24 18:31:28 +02002798static void dump_spu_fields(struct spu *spu)
2799{
2800 printf("Dumping spu fields at address %p:\n", spu);
2801
2802 DUMP_FIELD(spu, "0x%x", number);
2803 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02002804 DUMP_FIELD(spu, "0x%lx", local_store_phys);
2805 DUMP_FIELD(spu, "0x%p", local_store);
2806 DUMP_FIELD(spu, "0x%lx", ls_size);
2807 DUMP_FIELD(spu, "0x%x", node);
2808 DUMP_FIELD(spu, "0x%lx", flags);
2809 DUMP_FIELD(spu, "0x%lx", dar);
2810 DUMP_FIELD(spu, "0x%lx", dsisr);
2811 DUMP_FIELD(spu, "%d", class_0_pending);
2812 DUMP_FIELD(spu, "0x%lx", irqs[0]);
2813 DUMP_FIELD(spu, "0x%lx", irqs[1]);
2814 DUMP_FIELD(spu, "0x%lx", irqs[2]);
2815 DUMP_FIELD(spu, "0x%x", slb_replace);
2816 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02002817 DUMP_FIELD(spu, "0x%p", mm);
2818 DUMP_FIELD(spu, "0x%p", ctx);
2819 DUMP_FIELD(spu, "0x%p", rq);
2820 DUMP_FIELD(spu, "0x%p", timestamp);
2821 DUMP_FIELD(spu, "0x%lx", problem_phys);
2822 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01002823 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
2824 in_be32(&spu->problem->spu_runcntl_RW));
2825 DUMP_VALUE("0x%x", problem->spu_status_R,
2826 in_be32(&spu->problem->spu_status_R));
2827 DUMP_VALUE("0x%x", problem->spu_npc_RW,
2828 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02002829 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01002830 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02002831}
2832
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002833int
2834spu_inst_dump(unsigned long adr, long count, int praddr)
2835{
2836 return generic_inst_dump(adr, count, praddr, print_insn_spu);
2837}
2838
2839static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01002840{
2841 unsigned long offset, addr, ls_addr;
2842
2843 if (setjmp(bus_error_jmp) == 0) {
2844 catch_memory_errors = 1;
2845 sync();
2846 ls_addr = (unsigned long)spu_info[num].spu->local_store;
2847 sync();
2848 __delay(200);
2849 } else {
2850 catch_memory_errors = 0;
2851 printf("*** Error: accessing spu info for spu %d\n", num);
2852 return;
2853 }
2854 catch_memory_errors = 0;
2855
2856 if (scanhex(&offset))
2857 addr = ls_addr + offset;
2858 else
2859 addr = spu_info[num].dump_addr;
2860
2861 if (addr >= ls_addr + LS_SIZE) {
2862 printf("*** Error: address outside of local store\n");
2863 return;
2864 }
2865
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002866 switch (subcmd) {
2867 case 'i':
2868 addr += spu_inst_dump(addr, 16, 1);
2869 last_cmd = "sdi\n";
2870 break;
2871 default:
2872 prdump(addr, 64);
2873 addr += 64;
2874 last_cmd = "sd\n";
2875 break;
2876 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01002877
2878 spu_info[num].dump_addr = addr;
2879}
2880
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002881static int do_spu_cmd(void)
2882{
Michael Ellerman24a24c82006-11-23 00:46:41 +01002883 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002884 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002885
2886 cmd = inchar();
2887 switch (cmd) {
2888 case 's':
2889 stop_spus();
2890 break;
2891 case 'r':
2892 restart_spus();
2893 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002894 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002895 subcmd = inchar();
2896 if (isxdigit(subcmd) || subcmd == '\n')
2897 termch = subcmd;
2898 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01002899 scanhex(&num);
2900 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02002901 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01002902 return 0;
2903 }
2904
2905 switch (cmd) {
2906 case 'f':
2907 dump_spu_fields(spu_info[num].spu);
2908 break;
2909 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002910 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01002911 break;
2912 }
2913
Michael Ellermana8984972006-10-24 18:31:28 +02002914 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002915 default:
2916 return -1;
2917 }
2918
2919 return 0;
2920}
Arnd Bergmanne0555952006-11-27 19:18:55 +01002921#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002922static int do_spu_cmd(void)
2923{
2924 return -1;
2925}
2926#endif