blob: 121b04d165d1937b2805a5a1dabaaa30c0467f6f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
20#include <linux/cpumask.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100021#include <linux/module.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110022#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080023#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010024#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080025#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27#include <asm/ptrace.h>
28#include <asm/string.h>
29#include <asm/prom.h>
30#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100031#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/processor.h>
33#include <asm/pgtable.h>
34#include <asm/mmu.h>
35#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/cputable.h>
37#include <asm/rtas.h>
38#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100039#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020040#include <asm/spu.h>
41#include <asm/spu_priv1.h>
Stephen Rothwell1d135812006-11-13 14:50:28 +110042#include <asm/firmware.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100043
44#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +1000158extern void xmon_enter(void);
159extern void xmon_leave(void);
160
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000836 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 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 Mackerrasf78541d2005-10-28 22:53:37 +1000851 case 'p':
852 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 break;
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Ellerman51fae6d2005-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 Mackerrasf78541d2005-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 Ellerman51fae6d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 *startp = *endp = 0;
1222 if (pc == 0)
1223 return;
1224 if (setjmp(bus_error_jmp) == 0) {
1225 catch_memory_errors = 1;
1226 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001227 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 if (name != NULL) {
1229 *startp = pc - offset;
1230 *endp = pc - offset + size;
1231 }
1232 sync();
1233 }
1234 catch_memory_errors = 0;
1235}
1236
1237static int xmon_depth_to_print = 64;
1238
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001239#ifdef CONFIG_PPC64
1240#define LRSAVE_OFFSET 0x10
1241#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1242#define MARKER_OFFSET 0x60
1243#define REGS_OFFSET 0x70
1244#else
1245#define LRSAVE_OFFSET 4
1246#define REG_FRAME_MARKER 0x72656773
1247#define MARKER_OFFSET 8
1248#define REGS_OFFSET 16
1249#endif
1250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251static void xmon_show_stack(unsigned long sp, unsigned long lr,
1252 unsigned long pc)
1253{
1254 unsigned long ip;
1255 unsigned long newsp;
1256 unsigned long marker;
1257 int count = 0;
1258 struct pt_regs regs;
1259
1260 do {
1261 if (sp < PAGE_OFFSET) {
1262 if (sp != 0)
1263 printf("SP (%lx) is in userspace\n", sp);
1264 break;
1265 }
1266
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001267 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 || !mread(sp, &newsp, sizeof(unsigned long))) {
1269 printf("Couldn't read stack frame at %lx\n", sp);
1270 break;
1271 }
1272
1273 /*
1274 * For the first stack frame, try to work out if
1275 * LR and/or the saved LR value in the bottommost
1276 * stack frame are valid.
1277 */
1278 if ((pc | lr) != 0) {
1279 unsigned long fnstart, fnend;
1280 unsigned long nextip;
1281 int printip = 1;
1282
1283 get_function_bounds(pc, &fnstart, &fnend);
1284 nextip = 0;
1285 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001286 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 sizeof(unsigned long));
1288 if (lr == ip) {
1289 if (lr < PAGE_OFFSET
1290 || (fnstart <= lr && lr < fnend))
1291 printip = 0;
1292 } else if (lr == nextip) {
1293 printip = 0;
1294 } else if (lr >= PAGE_OFFSET
1295 && !(fnstart <= lr && lr < fnend)) {
1296 printf("[link register ] ");
1297 xmon_print_symbol(lr, " ", "\n");
1298 }
1299 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001300 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 xmon_print_symbol(ip, " ", " (unreliable)\n");
1302 }
1303 pc = lr = 0;
1304
1305 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001306 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 xmon_print_symbol(ip, " ", "\n");
1308 }
1309
1310 /* Look for "regshere" marker to see if this is
1311 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001312 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1313 && marker == REG_FRAME_MARKER) {
1314 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 != sizeof(regs)) {
1316 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001317 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 break;
1319 }
1320 printf("--- Exception: %lx %s at ", regs.trap,
1321 getvecname(TRAP(&regs)));
1322 pc = regs.nip;
1323 lr = regs.link;
1324 xmon_print_symbol(pc, " ", "\n");
1325 }
1326
1327 if (newsp == 0)
1328 break;
1329
1330 sp = newsp;
1331 } while (count++ < xmon_depth_to_print);
1332}
1333
1334static void backtrace(struct pt_regs *excp)
1335{
1336 unsigned long sp;
1337
1338 if (scanhex(&sp))
1339 xmon_show_stack(sp, 0, 0);
1340 else
1341 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1342 scannl();
1343}
1344
1345static void print_bug_trap(struct pt_regs *regs)
1346{
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001347 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 unsigned long addr;
1349
1350 if (regs->msr & MSR_PR)
1351 return; /* not in kernel */
1352 addr = regs->nip; /* address of trap instruction */
1353 if (addr < PAGE_OFFSET)
1354 return;
1355 bug = find_bug(regs->nip);
1356 if (bug == NULL)
1357 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001358 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 return;
1360
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001361#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001362 printf("kernel BUG at %s:%u!\n",
1363 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001364#else
1365 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1366#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367}
1368
1369void excprint(struct pt_regs *fp)
1370{
1371 unsigned long trap;
1372
1373#ifdef CONFIG_SMP
1374 printf("cpu 0x%x: ", smp_processor_id());
1375#endif /* CONFIG_SMP */
1376
1377 trap = TRAP(fp);
1378 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1379 printf(" pc: ");
1380 xmon_print_symbol(fp->nip, ": ", "\n");
1381
1382 printf(" lr: ", fp->link);
1383 xmon_print_symbol(fp->link, ": ", "\n");
1384
1385 printf(" sp: %lx\n", fp->gpr[1]);
1386 printf(" msr: %lx\n", fp->msr);
1387
1388 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1389 printf(" dar: %lx\n", fp->dar);
1390 if (trap != 0x380)
1391 printf(" dsisr: %lx\n", fp->dsisr);
1392 }
1393
1394 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001395#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001397#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 if (current) {
1399 printf(" pid = %ld, comm = %s\n",
1400 current->pid, current->comm);
1401 }
1402
1403 if (trap == 0x700)
1404 print_bug_trap(fp);
1405}
1406
1407void prregs(struct pt_regs *fp)
1408{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001409 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 unsigned long base;
1411 struct pt_regs regs;
1412
1413 if (scanhex(&base)) {
1414 if (setjmp(bus_error_jmp) == 0) {
1415 catch_memory_errors = 1;
1416 sync();
1417 regs = *(struct pt_regs *)base;
1418 sync();
1419 __delay(200);
1420 } else {
1421 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001422 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 base);
1424 return;
1425 }
1426 catch_memory_errors = 0;
1427 fp = &regs;
1428 }
1429
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001430#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 if (FULL_REGS(fp)) {
1432 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001433 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1435 } else {
1436 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001437 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1439 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001440#else
1441 for (n = 0; n < 32; ++n) {
1442 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1443 (n & 3) == 3? "\n": " ");
1444 if (n == 12 && !FULL_REGS(fp)) {
1445 printf("\n");
1446 break;
1447 }
1448 }
1449#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 printf("pc = ");
1451 xmon_print_symbol(fp->nip, " ", "\n");
1452 printf("lr = ");
1453 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001454 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1455 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001457 trap = TRAP(fp);
1458 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1459 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460}
1461
1462void cacheflush(void)
1463{
1464 int cmd;
1465 unsigned long nflush;
1466
1467 cmd = inchar();
1468 if (cmd != 'i')
1469 termch = cmd;
1470 scanhex((void *)&adrs);
1471 if (termch != '\n')
1472 termch = 0;
1473 nflush = 1;
1474 scanhex(&nflush);
1475 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1476 if (setjmp(bus_error_jmp) == 0) {
1477 catch_memory_errors = 1;
1478 sync();
1479
1480 if (cmd != 'i') {
1481 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1482 cflush((void *) adrs);
1483 } else {
1484 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1485 cinval((void *) adrs);
1486 }
1487 sync();
1488 /* wait a little while to see if we get a machine check */
1489 __delay(200);
1490 }
1491 catch_memory_errors = 0;
1492}
1493
1494unsigned long
1495read_spr(int n)
1496{
1497 unsigned int instrs[2];
1498 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001500#ifdef CONFIG_PPC64
1501 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 opd[0] = (unsigned long)instrs;
1504 opd[1] = 0;
1505 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001506 code = (unsigned long (*)(void)) opd;
1507#else
1508 code = (unsigned long (*)(void)) instrs;
1509#endif
1510
1511 /* mfspr r3,n; blr */
1512 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1513 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 store_inst(instrs);
1515 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
1517 if (setjmp(bus_error_jmp) == 0) {
1518 catch_memory_errors = 1;
1519 sync();
1520
1521 ret = code();
1522
1523 sync();
1524 /* wait a little while to see if we get a machine check */
1525 __delay(200);
1526 n = size;
1527 }
1528
1529 return ret;
1530}
1531
1532void
1533write_spr(int n, unsigned long val)
1534{
1535 unsigned int instrs[2];
1536 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001537#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 unsigned long opd[3];
1539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 opd[0] = (unsigned long)instrs;
1541 opd[1] = 0;
1542 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001543 code = (unsigned long (*)(unsigned long)) opd;
1544#else
1545 code = (unsigned long (*)(unsigned long)) instrs;
1546#endif
1547
1548 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1549 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 store_inst(instrs);
1551 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553 if (setjmp(bus_error_jmp) == 0) {
1554 catch_memory_errors = 1;
1555 sync();
1556
1557 code(val);
1558
1559 sync();
1560 /* wait a little while to see if we get a machine check */
1561 __delay(200);
1562 n = size;
1563 }
1564}
1565
1566static unsigned long regno;
1567extern char exc_prolog;
1568extern char dec_exc;
1569
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001570void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571{
1572 int cmd;
1573 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 cmd = skipbl();
1576 if (cmd == '\n') {
1577 unsigned long sp, toc;
1578 asm("mr %0,1" : "=r" (sp) :);
1579 asm("mr %0,2" : "=r" (toc) :);
1580
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001581 printf("msr = "REG" sprg0= "REG"\n",
1582 mfmsr(), mfspr(SPRN_SPRG0));
1583 printf("pvr = "REG" sprg1= "REG"\n",
1584 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1585 printf("dec = "REG" sprg2= "REG"\n",
1586 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1587 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1588 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589#ifdef CONFIG_PPC_ISERIES
Stephen Rothwell1d135812006-11-13 14:50:28 +11001590 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1591 struct paca_struct *ptrPaca;
1592 struct lppaca *ptrLpPaca;
1593 struct ItLpRegSave *ptrLpRegSave;
1594
1595 /* Dump out relevant Paca data areas. */
1596 printf("Paca: \n");
1597 ptrPaca = get_paca();
1598
1599 printf(" Local Processor Control Area (LpPaca): \n");
1600 ptrLpPaca = ptrPaca->lppaca_ptr;
1601 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1602 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1603 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1604 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1605 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1606
1607 printf(" Local Processor Register Save Area (LpRegSave): \n");
1608 ptrLpRegSave = ptrPaca->reg_save_ptr;
1609 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1610 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1611 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1612 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1613 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1614 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616#endif
1617
1618 return;
1619 }
1620
1621 scanhex(&regno);
1622 switch (cmd) {
1623 case 'w':
1624 val = read_spr(regno);
1625 scanhex(&val);
1626 write_spr(regno, val);
1627 /* fall through */
1628 case 'r':
1629 printf("spr %lx = %lx\n", regno, read_spr(regno));
1630 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 }
1632 scannl();
1633}
1634
1635/*
1636 * Stuff for reading and writing memory safely
1637 */
1638int
1639mread(unsigned long adrs, void *buf, int size)
1640{
1641 volatile int n;
1642 char *p, *q;
1643
1644 n = 0;
1645 if (setjmp(bus_error_jmp) == 0) {
1646 catch_memory_errors = 1;
1647 sync();
1648 p = (char *)adrs;
1649 q = (char *)buf;
1650 switch (size) {
1651 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001652 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 break;
1654 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001655 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 break;
1657 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001658 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 break;
1660 default:
1661 for( ; n < size; ++n) {
1662 *q++ = *p++;
1663 sync();
1664 }
1665 }
1666 sync();
1667 /* wait a little while to see if we get a machine check */
1668 __delay(200);
1669 n = size;
1670 }
1671 catch_memory_errors = 0;
1672 return n;
1673}
1674
1675int
1676mwrite(unsigned long adrs, void *buf, int size)
1677{
1678 volatile int n;
1679 char *p, *q;
1680
1681 n = 0;
1682 if (setjmp(bus_error_jmp) == 0) {
1683 catch_memory_errors = 1;
1684 sync();
1685 p = (char *) adrs;
1686 q = (char *) buf;
1687 switch (size) {
1688 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001689 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 break;
1691 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001692 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 break;
1694 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001695 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 break;
1697 default:
1698 for ( ; n < size; ++n) {
1699 *p++ = *q++;
1700 sync();
1701 }
1702 }
1703 sync();
1704 /* wait a little while to see if we get a machine check */
1705 __delay(200);
1706 n = size;
1707 } else {
1708 printf("*** Error writing address %x\n", adrs + n);
1709 }
1710 catch_memory_errors = 0;
1711 return n;
1712}
1713
1714static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001715static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716static char *fault_chars[] = { "--", "**", "##" };
1717
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001718static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001720 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 switch (TRAP(regs)) {
1722 case 0x200:
1723 fault_type = 0;
1724 break;
1725 case 0x300:
1726 case 0x380:
1727 fault_type = 1;
1728 break;
1729 default:
1730 fault_type = 2;
1731 }
1732
1733 longjmp(bus_error_jmp, 1);
1734
1735 return 0;
1736}
1737
1738#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1739
1740void
1741byterev(unsigned char *val, int size)
1742{
1743 int t;
1744
1745 switch (size) {
1746 case 2:
1747 SWAP(val[0], val[1], t);
1748 break;
1749 case 4:
1750 SWAP(val[0], val[3], t);
1751 SWAP(val[1], val[2], t);
1752 break;
1753 case 8: /* is there really any use for this? */
1754 SWAP(val[0], val[7], t);
1755 SWAP(val[1], val[6], t);
1756 SWAP(val[2], val[5], t);
1757 SWAP(val[3], val[4], t);
1758 break;
1759 }
1760}
1761
1762static int brev;
1763static int mnoread;
1764
1765static char *memex_help_string =
1766 "Memory examine command usage:\n"
1767 "m [addr] [flags] examine/change memory\n"
1768 " addr is optional. will start where left off.\n"
1769 " flags may include chars from this set:\n"
1770 " b modify by bytes (default)\n"
1771 " w modify by words (2 byte)\n"
1772 " l modify by longs (4 byte)\n"
1773 " d modify by doubleword (8 byte)\n"
1774 " r toggle reverse byte order mode\n"
1775 " n do not read memory (for i/o spaces)\n"
1776 " . ok to read (default)\n"
1777 "NOTE: flags are saved as defaults\n"
1778 "";
1779
1780static char *memex_subcmd_help_string =
1781 "Memory examine subcommands:\n"
1782 " hexval write this val to current location\n"
1783 " 'string' write chars from string to this location\n"
1784 " ' increment address\n"
1785 " ^ decrement address\n"
1786 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1787 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1788 " ` clear no-read flag\n"
1789 " ; stay at this addr\n"
1790 " v change to byte mode\n"
1791 " w change to word (2 byte) mode\n"
1792 " l change to long (4 byte) mode\n"
1793 " u change to doubleword (8 byte) mode\n"
1794 " m addr change current addr\n"
1795 " n toggle no-read flag\n"
1796 " r toggle byte reverse flag\n"
1797 " < count back up count bytes\n"
1798 " > count skip forward count bytes\n"
1799 " x exit this mode\n"
1800 "";
1801
1802void
1803memex(void)
1804{
1805 int cmd, inc, i, nslash;
1806 unsigned long n;
1807 unsigned char val[16];
1808
1809 scanhex((void *)&adrs);
1810 cmd = skipbl();
1811 if (cmd == '?') {
1812 printf(memex_help_string);
1813 return;
1814 } else {
1815 termch = cmd;
1816 }
1817 last_cmd = "m\n";
1818 while ((cmd = skipbl()) != '\n') {
1819 switch( cmd ){
1820 case 'b': size = 1; break;
1821 case 'w': size = 2; break;
1822 case 'l': size = 4; break;
1823 case 'd': size = 8; break;
1824 case 'r': brev = !brev; break;
1825 case 'n': mnoread = 1; break;
1826 case '.': mnoread = 0; break;
1827 }
1828 }
1829 if( size <= 0 )
1830 size = 1;
1831 else if( size > 8 )
1832 size = 8;
1833 for(;;){
1834 if (!mnoread)
1835 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001836 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 if (!mnoread) {
1838 if (brev)
1839 byterev(val, size);
1840 putchar(' ');
1841 for (i = 0; i < n; ++i)
1842 printf("%.2x", val[i]);
1843 for (; i < size; ++i)
1844 printf("%s", fault_chars[fault_type]);
1845 }
1846 putchar(' ');
1847 inc = size;
1848 nslash = 0;
1849 for(;;){
1850 if( scanhex(&n) ){
1851 for (i = 0; i < size; ++i)
1852 val[i] = n >> (i * 8);
1853 if (!brev)
1854 byterev(val, size);
1855 mwrite(adrs, val, size);
1856 inc = size;
1857 }
1858 cmd = skipbl();
1859 if (cmd == '\n')
1860 break;
1861 inc = 0;
1862 switch (cmd) {
1863 case '\'':
1864 for(;;){
1865 n = inchar();
1866 if( n == '\\' )
1867 n = bsesc();
1868 else if( n == '\'' )
1869 break;
1870 for (i = 0; i < size; ++i)
1871 val[i] = n >> (i * 8);
1872 if (!brev)
1873 byterev(val, size);
1874 mwrite(adrs, val, size);
1875 adrs += size;
1876 }
1877 adrs -= size;
1878 inc = size;
1879 break;
1880 case ',':
1881 adrs += size;
1882 break;
1883 case '.':
1884 mnoread = 0;
1885 break;
1886 case ';':
1887 break;
1888 case 'x':
1889 case EOF:
1890 scannl();
1891 return;
1892 case 'b':
1893 case 'v':
1894 size = 1;
1895 break;
1896 case 'w':
1897 size = 2;
1898 break;
1899 case 'l':
1900 size = 4;
1901 break;
1902 case 'u':
1903 size = 8;
1904 break;
1905 case '^':
1906 adrs -= size;
1907 break;
1908 break;
1909 case '/':
1910 if (nslash > 0)
1911 adrs -= 1 << nslash;
1912 else
1913 nslash = 0;
1914 nslash += 4;
1915 adrs += 1 << nslash;
1916 break;
1917 case '\\':
1918 if (nslash < 0)
1919 adrs += 1 << -nslash;
1920 else
1921 nslash = 0;
1922 nslash -= 4;
1923 adrs -= 1 << -nslash;
1924 break;
1925 case 'm':
1926 scanhex((void *)&adrs);
1927 break;
1928 case 'n':
1929 mnoread = 1;
1930 break;
1931 case 'r':
1932 brev = !brev;
1933 break;
1934 case '<':
1935 n = size;
1936 scanhex(&n);
1937 adrs -= n;
1938 break;
1939 case '>':
1940 n = size;
1941 scanhex(&n);
1942 adrs += n;
1943 break;
1944 case '?':
1945 printf(memex_subcmd_help_string);
1946 break;
1947 }
1948 }
1949 adrs += inc;
1950 }
1951}
1952
1953int
1954bsesc(void)
1955{
1956 int c;
1957
1958 c = inchar();
1959 switch( c ){
1960 case 'n': c = '\n'; break;
1961 case 'r': c = '\r'; break;
1962 case 'b': c = '\b'; break;
1963 case 't': c = '\t'; break;
1964 }
1965 return c;
1966}
1967
Olaf Hering7e5b5932006-03-08 20:40:28 +01001968static void xmon_rawdump (unsigned long adrs, long ndump)
1969{
1970 long n, m, r, nr;
1971 unsigned char temp[16];
1972
1973 for (n = ndump; n > 0;) {
1974 r = n < 16? n: 16;
1975 nr = mread(adrs, temp, r);
1976 adrs += nr;
1977 for (m = 0; m < r; ++m) {
1978 if (m < nr)
1979 printf("%.2x", temp[m]);
1980 else
1981 printf("%s", fault_chars[fault_type]);
1982 }
1983 n -= r;
1984 if (nr < r)
1985 break;
1986 }
1987 printf("\n");
1988}
1989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
1991 || ('a' <= (c) && (c) <= 'f') \
1992 || ('A' <= (c) && (c) <= 'F'))
1993void
1994dump(void)
1995{
1996 int c;
1997
1998 c = inchar();
1999 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2000 termch = c;
2001 scanhex((void *)&adrs);
2002 if (termch != '\n')
2003 termch = 0;
2004 if (c == 'i') {
2005 scanhex(&nidump);
2006 if (nidump == 0)
2007 nidump = 16;
2008 else if (nidump > MAX_DUMP)
2009 nidump = MAX_DUMP;
2010 adrs += ppc_inst_dump(adrs, nidump, 1);
2011 last_cmd = "di\n";
Olaf Hering7e5b5932006-03-08 20:40:28 +01002012 } else if (c == 'r') {
2013 scanhex(&ndump);
2014 if (ndump == 0)
2015 ndump = 64;
2016 xmon_rawdump(adrs, ndump);
2017 adrs += ndump;
2018 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 } else {
2020 scanhex(&ndump);
2021 if (ndump == 0)
2022 ndump = 64;
2023 else if (ndump > MAX_DUMP)
2024 ndump = MAX_DUMP;
2025 prdump(adrs, ndump);
2026 adrs += ndump;
2027 last_cmd = "d\n";
2028 }
2029}
2030
2031void
2032prdump(unsigned long adrs, long ndump)
2033{
2034 long n, m, c, r, nr;
2035 unsigned char temp[16];
2036
2037 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002038 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 putchar(' ');
2040 r = n < 16? n: 16;
2041 nr = mread(adrs, temp, r);
2042 adrs += nr;
2043 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002044 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2045 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 if (m < nr)
2047 printf("%.2x", temp[m]);
2048 else
2049 printf("%s", fault_chars[fault_type]);
2050 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002051 for (; m < 16; ++m) {
2052 if ((m & (sizeof(long) - 1)) == 0)
2053 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 printf(" |");
2057 for (m = 0; m < r; ++m) {
2058 if (m < nr) {
2059 c = temp[m];
2060 putchar(' ' <= c && c <= '~'? c: '.');
2061 } else
2062 putchar(' ');
2063 }
2064 n -= r;
2065 for (; m < 16; ++m)
2066 putchar(' ');
2067 printf("|\n");
2068 if (nr < r)
2069 break;
2070 }
2071}
2072
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002073typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002076generic_inst_dump(unsigned long adr, long count, int praddr,
2077 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078{
2079 int nr, dotted;
2080 unsigned long first_adr;
2081 unsigned long inst, last_inst = 0;
2082 unsigned char val[4];
2083
2084 dotted = 0;
2085 for (first_adr = adr; count > 0; --count, adr += 4) {
2086 nr = mread(adr, val, 4);
2087 if (nr == 0) {
2088 if (praddr) {
2089 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002090 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 }
2092 break;
2093 }
2094 inst = GETWORD(val);
2095 if (adr > first_adr && inst == last_inst) {
2096 if (!dotted) {
2097 printf(" ...\n");
2098 dotted = 1;
2099 }
2100 continue;
2101 }
2102 dotted = 0;
2103 last_inst = inst;
2104 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002105 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002107 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 printf("\n");
2109 }
2110 return adr - first_adr;
2111}
2112
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002113int
2114ppc_inst_dump(unsigned long adr, long count, int praddr)
2115{
2116 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2117}
2118
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119void
2120print_address(unsigned long addr)
2121{
2122 xmon_print_symbol(addr, "\t# ", "");
2123}
2124
2125
2126/*
2127 * Memory operations - move, set, print differences
2128 */
2129static unsigned long mdest; /* destination address */
2130static unsigned long msrc; /* source address */
2131static unsigned long mval; /* byte value to set memory to */
2132static unsigned long mcount; /* # bytes to affect */
2133static unsigned long mdiffs; /* max # differences to print */
2134
2135void
2136memops(int cmd)
2137{
2138 scanhex((void *)&mdest);
2139 if( termch != '\n' )
2140 termch = 0;
2141 scanhex((void *)(cmd == 's'? &mval: &msrc));
2142 if( termch != '\n' )
2143 termch = 0;
2144 scanhex((void *)&mcount);
2145 switch( cmd ){
2146 case 'm':
2147 memmove((void *)mdest, (void *)msrc, mcount);
2148 break;
2149 case 's':
2150 memset((void *)mdest, mval, mcount);
2151 break;
2152 case 'd':
2153 if( termch != '\n' )
2154 termch = 0;
2155 scanhex((void *)&mdiffs);
2156 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2157 break;
2158 }
2159}
2160
2161void
2162memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2163{
2164 unsigned n, prt;
2165
2166 prt = 0;
2167 for( n = nb; n > 0; --n )
2168 if( *p1++ != *p2++ )
2169 if( ++prt <= maxpr )
2170 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2171 p1[-1], p2 - 1, p2[-1]);
2172 if( prt > maxpr )
2173 printf("Total of %d differences\n", prt);
2174}
2175
2176static unsigned mend;
2177static unsigned mask;
2178
2179void
2180memlocate(void)
2181{
2182 unsigned a, n;
2183 unsigned char val[4];
2184
2185 last_cmd = "ml";
2186 scanhex((void *)&mdest);
2187 if (termch != '\n') {
2188 termch = 0;
2189 scanhex((void *)&mend);
2190 if (termch != '\n') {
2191 termch = 0;
2192 scanhex((void *)&mval);
2193 mask = ~0;
2194 if (termch != '\n') termch = 0;
2195 scanhex((void *)&mask);
2196 }
2197 }
2198 n = 0;
2199 for (a = mdest; a < mend; a += 4) {
2200 if (mread(a, val, 4) == 4
2201 && ((GETWORD(val) ^ mval) & mask) == 0) {
2202 printf("%.16x: %.16x\n", a, GETWORD(val));
2203 if (++n >= 10)
2204 break;
2205 }
2206 }
2207}
2208
2209static unsigned long mskip = 0x1000;
2210static unsigned long mlim = 0xffffffff;
2211
2212void
2213memzcan(void)
2214{
2215 unsigned char v;
2216 unsigned a;
2217 int ok, ook;
2218
2219 scanhex(&mdest);
2220 if (termch != '\n') termch = 0;
2221 scanhex(&mskip);
2222 if (termch != '\n') termch = 0;
2223 scanhex(&mlim);
2224 ook = 0;
2225 for (a = mdest; a < mlim; a += mskip) {
2226 ok = mread(a, &v, 1);
2227 if (ok && !ook) {
2228 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 } else if (!ok && ook)
2230 printf("%.8x\n", a - mskip);
2231 ook = ok;
2232 if (a + mskip < a)
2233 break;
2234 }
2235 if (ook)
2236 printf("%.8x\n", a - mskip);
2237}
2238
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002239void proccall(void)
2240{
2241 unsigned long args[8];
2242 unsigned long ret;
2243 int i;
2244 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2245 unsigned long, unsigned long, unsigned long,
2246 unsigned long, unsigned long, unsigned long);
2247 callfunc_t func;
2248
2249 if (!scanhex(&adrs))
2250 return;
2251 if (termch != '\n')
2252 termch = 0;
2253 for (i = 0; i < 8; ++i)
2254 args[i] = 0;
2255 for (i = 0; i < 8; ++i) {
2256 if (!scanhex(&args[i]) || termch == '\n')
2257 break;
2258 termch = 0;
2259 }
2260 func = (callfunc_t) adrs;
2261 ret = 0;
2262 if (setjmp(bus_error_jmp) == 0) {
2263 catch_memory_errors = 1;
2264 sync();
2265 ret = func(args[0], args[1], args[2], args[3],
2266 args[4], args[5], args[6], args[7]);
2267 sync();
2268 printf("return value is %x\n", ret);
2269 } else {
2270 printf("*** %x exception occurred\n", fault_except);
2271 }
2272 catch_memory_errors = 0;
2273}
2274
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275/* Input scanning routines */
2276int
2277skipbl(void)
2278{
2279 int c;
2280
2281 if( termch != 0 ){
2282 c = termch;
2283 termch = 0;
2284 } else
2285 c = inchar();
2286 while( c == ' ' || c == '\t' )
2287 c = inchar();
2288 return c;
2289}
2290
2291#define N_PTREGS 44
2292static char *regnames[N_PTREGS] = {
2293 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2294 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2295 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2296 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002297 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2298#ifdef CONFIG_PPC64
2299 "softe",
2300#else
2301 "mq",
2302#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 "trap", "dar", "dsisr", "res"
2304};
2305
2306int
2307scanhex(unsigned long *vp)
2308{
2309 int c, d;
2310 unsigned long v;
2311
2312 c = skipbl();
2313 if (c == '%') {
2314 /* parse register name */
2315 char regname[8];
2316 int i;
2317
2318 for (i = 0; i < sizeof(regname) - 1; ++i) {
2319 c = inchar();
2320 if (!isalnum(c)) {
2321 termch = c;
2322 break;
2323 }
2324 regname[i] = c;
2325 }
2326 regname[i] = 0;
2327 for (i = 0; i < N_PTREGS; ++i) {
2328 if (strcmp(regnames[i], regname) == 0) {
2329 if (xmon_regs == NULL) {
2330 printf("regs not available\n");
2331 return 0;
2332 }
2333 *vp = ((unsigned long *)xmon_regs)[i];
2334 return 1;
2335 }
2336 }
2337 printf("invalid register name '%%%s'\n", regname);
2338 return 0;
2339 }
2340
2341 /* skip leading "0x" if any */
2342
2343 if (c == '0') {
2344 c = inchar();
2345 if (c == 'x') {
2346 c = inchar();
2347 } else {
2348 d = hexdigit(c);
2349 if (d == EOF) {
2350 termch = c;
2351 *vp = 0;
2352 return 1;
2353 }
2354 }
2355 } else if (c == '$') {
2356 int i;
2357 for (i=0; i<63; i++) {
2358 c = inchar();
2359 if (isspace(c)) {
2360 termch = c;
2361 break;
2362 }
2363 tmpstr[i] = c;
2364 }
2365 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002366 *vp = 0;
2367 if (setjmp(bus_error_jmp) == 0) {
2368 catch_memory_errors = 1;
2369 sync();
2370 *vp = kallsyms_lookup_name(tmpstr);
2371 sync();
2372 }
2373 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 if (!(*vp)) {
2375 printf("unknown symbol '%s'\n", tmpstr);
2376 return 0;
2377 }
2378 return 1;
2379 }
2380
2381 d = hexdigit(c);
2382 if (d == EOF) {
2383 termch = c;
2384 return 0;
2385 }
2386 v = 0;
2387 do {
2388 v = (v << 4) + d;
2389 c = inchar();
2390 d = hexdigit(c);
2391 } while (d != EOF);
2392 termch = c;
2393 *vp = v;
2394 return 1;
2395}
2396
2397void
2398scannl(void)
2399{
2400 int c;
2401
2402 c = termch;
2403 termch = 0;
2404 while( c != '\n' )
2405 c = inchar();
2406}
2407
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002408int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409{
2410 if( '0' <= c && c <= '9' )
2411 return c - '0';
2412 if( 'A' <= c && c <= 'F' )
2413 return c - ('A' - 10);
2414 if( 'a' <= c && c <= 'f' )
2415 return c - ('a' - 10);
2416 return EOF;
2417}
2418
2419void
2420getstring(char *s, int size)
2421{
2422 int c;
2423
2424 c = skipbl();
2425 do {
2426 if( size > 1 ){
2427 *s++ = c;
2428 --size;
2429 }
2430 c = inchar();
2431 } while( c != ' ' && c != '\t' && c != '\n' );
2432 termch = c;
2433 *s = 0;
2434}
2435
2436static char line[256];
2437static char *lineptr;
2438
2439void
2440flush_input(void)
2441{
2442 lineptr = NULL;
2443}
2444
2445int
2446inchar(void)
2447{
2448 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002449 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 lineptr = NULL;
2451 return EOF;
2452 }
2453 lineptr = line;
2454 }
2455 return *lineptr++;
2456}
2457
2458void
2459take_input(char *str)
2460{
2461 lineptr = str;
2462}
2463
2464
2465static void
2466symbol_lookup(void)
2467{
2468 int type = inchar();
2469 unsigned long addr;
2470 static char tmp[64];
2471
2472 switch (type) {
2473 case 'a':
2474 if (scanhex(&addr))
2475 xmon_print_symbol(addr, ": ", "\n");
2476 termch = 0;
2477 break;
2478 case 's':
2479 getstring(tmp, 64);
2480 if (setjmp(bus_error_jmp) == 0) {
2481 catch_memory_errors = 1;
2482 sync();
2483 addr = kallsyms_lookup_name(tmp);
2484 if (addr)
2485 printf("%s: %lx\n", tmp, addr);
2486 else
2487 printf("Symbol '%s' not found.\n", tmp);
2488 sync();
2489 }
2490 catch_memory_errors = 0;
2491 termch = 0;
2492 break;
2493 }
2494}
2495
2496
2497/* Print an address in numeric and symbolic form (if possible) */
2498static void xmon_print_symbol(unsigned long address, const char *mid,
2499 const char *after)
2500{
2501 char *modname;
2502 const char *name = NULL;
2503 unsigned long offset, size;
2504
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002505 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 if (setjmp(bus_error_jmp) == 0) {
2507 catch_memory_errors = 1;
2508 sync();
2509 name = kallsyms_lookup(address, &size, &offset, &modname,
2510 tmpstr);
2511 sync();
2512 /* wait a little while to see if we get a machine check */
2513 __delay(200);
2514 }
2515
2516 catch_memory_errors = 0;
2517
2518 if (name) {
2519 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2520 if (modname)
2521 printf(" [%s]", modname);
2522 }
2523 printf("%s", after);
2524}
2525
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002526#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527static void dump_slb(void)
2528{
2529 int i;
2530 unsigned long tmp;
2531
2532 printf("SLB contents of cpu %x\n", smp_processor_id());
2533
2534 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2535 asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
2536 printf("%02d %016lx ", i, tmp);
2537
2538 asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
2539 printf("%016lx\n", tmp);
2540 }
2541}
2542
2543static void dump_stab(void)
2544{
2545 int i;
2546 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2547
2548 printf("Segment table contents of cpu %x\n", smp_processor_id());
2549
2550 for (i = 0; i < PAGE_SIZE/16; i++) {
2551 unsigned long a, b;
2552
2553 a = *tmp++;
2554 b = *tmp++;
2555
2556 if (a || b) {
2557 printf("%03d %016lx ", i, a);
2558 printf("%016lx\n", b);
2559 }
2560 }
2561}
2562
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002563void dump_segments(void)
2564{
2565 if (cpu_has_feature(CPU_FTR_SLB))
2566 dump_slb();
2567 else
2568 dump_stab();
2569}
2570#endif
2571
2572#ifdef CONFIG_PPC_STD_MMU_32
2573void dump_segments(void)
2574{
2575 int i;
2576
2577 printf("sr0-15 =");
2578 for (i = 0; i < 16; ++i)
2579 printf(" %x", mfsrin(i));
2580 printf("\n");
2581}
2582#endif
2583
Olaf Heringb13cfd12005-08-04 19:26:42 +02002584void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002586#ifdef CONFIG_PPC_ISERIES
2587 if (firmware_has_feature(FW_FEATURE_ISERIES))
2588 return;
2589#endif
Olaf Heringb13cfd12005-08-04 19:26:42 +02002590 if (enable) {
2591 __debugger = xmon;
2592 __debugger_ipi = xmon_ipi;
2593 __debugger_bpt = xmon_bpt;
2594 __debugger_sstep = xmon_sstep;
2595 __debugger_iabr_match = xmon_iabr_match;
2596 __debugger_dabr_match = xmon_dabr_match;
2597 __debugger_fault_handler = xmon_fault_handler;
2598 } else {
2599 __debugger = NULL;
2600 __debugger_ipi = NULL;
2601 __debugger_bpt = NULL;
2602 __debugger_sstep = NULL;
2603 __debugger_iabr_match = NULL;
2604 __debugger_dabr_match = NULL;
2605 __debugger_fault_handler = NULL;
2606 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002607 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002609
2610#ifdef CONFIG_MAGIC_SYSRQ
David Howells7d12e782006-10-05 14:55:46 +01002611static void sysrq_handle_xmon(int key, struct tty_struct *tty)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002612{
2613 /* ensure xmon is enabled */
2614 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002615 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002616}
2617
2618static struct sysrq_key_op sysrq_xmon_op =
2619{
2620 .handler = sysrq_handle_xmon,
2621 .help_msg = "Xmon",
2622 .action_msg = "Entering xmon",
2623};
2624
2625static int __init setup_xmon_sysrq(void)
2626{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002627#ifdef CONFIG_PPC_ISERIES
2628 if (firmware_has_feature(FW_FEATURE_ISERIES))
2629 return 0;
2630#endif
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002631 register_sysrq_key('x', &sysrq_xmon_op);
2632 return 0;
2633}
2634__initcall(setup_xmon_sysrq);
2635#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002636
Olaf Heringf5e6a282007-06-24 16:57:08 +10002637static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002638
2639static int __init early_parse_xmon(char *p)
2640{
2641 if (!p || strncmp(p, "early", 5) == 0) {
2642 /* just "xmon" is equivalent to "xmon=early" */
2643 xmon_init(1);
2644 xmon_early = 1;
2645 } else if (strncmp(p, "on", 2) == 0)
2646 xmon_init(1);
2647 else if (strncmp(p, "off", 3) == 0)
2648 xmon_off = 1;
2649 else if (strncmp(p, "nobt", 4) == 0)
2650 xmon_no_auto_backtrace = 1;
2651 else
2652 return 1;
2653
2654 return 0;
2655}
2656early_param("xmon", early_parse_xmon);
2657
2658void __init xmon_setup(void)
2659{
2660#ifdef CONFIG_XMON_DEFAULT
2661 if (!xmon_off)
2662 xmon_init(1);
2663#endif
2664 if (xmon_early)
2665 debugger(NULL);
2666}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002667
Arnd Bergmanne0555952006-11-27 19:18:55 +01002668#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002669
2670struct spu_info {
2671 struct spu *spu;
2672 u64 saved_mfc_sr1_RW;
2673 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002674 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002675 u8 stopped_ok;
2676};
2677
2678#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2679
2680static struct spu_info spu_info[XMON_NUM_SPUS];
2681
2682void xmon_register_spus(struct list_head *list)
2683{
2684 struct spu *spu;
2685
2686 list_for_each_entry(spu, list, full_list) {
2687 if (spu->number >= XMON_NUM_SPUS) {
2688 WARN_ON(1);
2689 continue;
2690 }
2691
2692 spu_info[spu->number].spu = spu;
2693 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002694 spu_info[spu->number].dump_addr = (unsigned long)
2695 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002696 }
2697}
2698
2699static void stop_spus(void)
2700{
2701 struct spu *spu;
2702 int i;
2703 u64 tmp;
2704
2705 for (i = 0; i < XMON_NUM_SPUS; i++) {
2706 if (!spu_info[i].spu)
2707 continue;
2708
2709 if (setjmp(bus_error_jmp) == 0) {
2710 catch_memory_errors = 1;
2711 sync();
2712
2713 spu = spu_info[i].spu;
2714
2715 spu_info[i].saved_spu_runcntl_RW =
2716 in_be32(&spu->problem->spu_runcntl_RW);
2717
2718 tmp = spu_mfc_sr1_get(spu);
2719 spu_info[i].saved_mfc_sr1_RW = tmp;
2720
2721 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2722 spu_mfc_sr1_set(spu, tmp);
2723
2724 sync();
2725 __delay(200);
2726
2727 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01002728
2729 printf("Stopped spu %.2d (was %s)\n", i,
2730 spu_info[i].saved_spu_runcntl_RW ?
2731 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002732 } else {
2733 catch_memory_errors = 0;
2734 printf("*** Error stopping spu %.2d\n", i);
2735 }
2736 catch_memory_errors = 0;
2737 }
2738}
2739
2740static void restart_spus(void)
2741{
2742 struct spu *spu;
2743 int i;
2744
2745 for (i = 0; i < XMON_NUM_SPUS; i++) {
2746 if (!spu_info[i].spu)
2747 continue;
2748
2749 if (!spu_info[i].stopped_ok) {
2750 printf("*** Error, spu %d was not successfully stopped"
2751 ", not restarting\n", i);
2752 continue;
2753 }
2754
2755 if (setjmp(bus_error_jmp) == 0) {
2756 catch_memory_errors = 1;
2757 sync();
2758
2759 spu = spu_info[i].spu;
2760 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2761 out_be32(&spu->problem->spu_runcntl_RW,
2762 spu_info[i].saved_spu_runcntl_RW);
2763
2764 sync();
2765 __delay(200);
2766
2767 printf("Restarted spu %.2d\n", i);
2768 } else {
2769 catch_memory_errors = 0;
2770 printf("*** Error restarting spu %.2d\n", i);
2771 }
2772 catch_memory_errors = 0;
2773 }
2774}
2775
Michael Ellermana8984972006-10-24 18:31:28 +02002776#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01002777#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02002778do { \
2779 if (setjmp(bus_error_jmp) == 0) { \
2780 catch_memory_errors = 1; \
2781 sync(); \
2782 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01002783 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02002784 sync(); \
2785 __delay(200); \
2786 } else { \
2787 catch_memory_errors = 0; \
2788 printf(" %-*s = *** Error reading field.\n", \
2789 DUMP_WIDTH, #field); \
2790 } \
2791 catch_memory_errors = 0; \
2792} while (0)
2793
Michael Ellerman437a0702006-11-23 00:46:39 +01002794#define DUMP_FIELD(obj, format, field) \
2795 DUMP_VALUE(format, field, obj->field)
2796
Michael Ellermana8984972006-10-24 18:31:28 +02002797static void dump_spu_fields(struct spu *spu)
2798{
2799 printf("Dumping spu fields at address %p:\n", spu);
2800
2801 DUMP_FIELD(spu, "0x%x", number);
2802 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02002803 DUMP_FIELD(spu, "0x%lx", local_store_phys);
2804 DUMP_FIELD(spu, "0x%p", local_store);
2805 DUMP_FIELD(spu, "0x%lx", ls_size);
2806 DUMP_FIELD(spu, "0x%x", node);
2807 DUMP_FIELD(spu, "0x%lx", flags);
2808 DUMP_FIELD(spu, "0x%lx", dar);
2809 DUMP_FIELD(spu, "0x%lx", dsisr);
2810 DUMP_FIELD(spu, "%d", class_0_pending);
2811 DUMP_FIELD(spu, "0x%lx", irqs[0]);
2812 DUMP_FIELD(spu, "0x%lx", irqs[1]);
2813 DUMP_FIELD(spu, "0x%lx", irqs[2]);
2814 DUMP_FIELD(spu, "0x%x", slb_replace);
2815 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02002816 DUMP_FIELD(spu, "0x%p", mm);
2817 DUMP_FIELD(spu, "0x%p", ctx);
2818 DUMP_FIELD(spu, "0x%p", rq);
2819 DUMP_FIELD(spu, "0x%p", timestamp);
2820 DUMP_FIELD(spu, "0x%lx", problem_phys);
2821 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01002822 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
2823 in_be32(&spu->problem->spu_runcntl_RW));
2824 DUMP_VALUE("0x%x", problem->spu_status_R,
2825 in_be32(&spu->problem->spu_status_R));
2826 DUMP_VALUE("0x%x", problem->spu_npc_RW,
2827 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02002828 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01002829 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02002830}
2831
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002832int
2833spu_inst_dump(unsigned long adr, long count, int praddr)
2834{
2835 return generic_inst_dump(adr, count, praddr, print_insn_spu);
2836}
2837
2838static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01002839{
2840 unsigned long offset, addr, ls_addr;
2841
2842 if (setjmp(bus_error_jmp) == 0) {
2843 catch_memory_errors = 1;
2844 sync();
2845 ls_addr = (unsigned long)spu_info[num].spu->local_store;
2846 sync();
2847 __delay(200);
2848 } else {
2849 catch_memory_errors = 0;
2850 printf("*** Error: accessing spu info for spu %d\n", num);
2851 return;
2852 }
2853 catch_memory_errors = 0;
2854
2855 if (scanhex(&offset))
2856 addr = ls_addr + offset;
2857 else
2858 addr = spu_info[num].dump_addr;
2859
2860 if (addr >= ls_addr + LS_SIZE) {
2861 printf("*** Error: address outside of local store\n");
2862 return;
2863 }
2864
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002865 switch (subcmd) {
2866 case 'i':
2867 addr += spu_inst_dump(addr, 16, 1);
2868 last_cmd = "sdi\n";
2869 break;
2870 default:
2871 prdump(addr, 64);
2872 addr += 64;
2873 last_cmd = "sd\n";
2874 break;
2875 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01002876
2877 spu_info[num].dump_addr = addr;
2878}
2879
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002880static int do_spu_cmd(void)
2881{
Michael Ellerman24a24c82006-11-23 00:46:41 +01002882 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002883 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002884
2885 cmd = inchar();
2886 switch (cmd) {
2887 case 's':
2888 stop_spus();
2889 break;
2890 case 'r':
2891 restart_spus();
2892 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002893 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002894 subcmd = inchar();
2895 if (isxdigit(subcmd) || subcmd == '\n')
2896 termch = subcmd;
2897 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01002898 scanhex(&num);
2899 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02002900 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01002901 return 0;
2902 }
2903
2904 switch (cmd) {
2905 case 'f':
2906 dump_spu_fields(spu_info[num].spu);
2907 break;
2908 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002909 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01002910 break;
2911 }
2912
Michael Ellermana8984972006-10-24 18:31:28 +02002913 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002914 default:
2915 return -1;
2916 }
2917
2918 return 0;
2919}
Arnd Bergmanne0555952006-11-27 19:18:55 +01002920#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002921static int do_spu_cmd(void)
2922{
2923 return -1;
2924}
2925#endif