blob: 8adad1444a51f3fca949bc4d0e7ec3ead0f3d93e [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.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/errno.h>
12#include <linux/sched.h>
13#include <linux/smp.h>
14#include <linux/mm.h>
15#include <linux/reboot.h>
16#include <linux/delay.h>
17#include <linux/kallsyms.h>
18#include <linux/cpumask.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100019#include <linux/module.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110020#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080021#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
23#include <asm/ptrace.h>
24#include <asm/string.h>
25#include <asm/prom.h>
26#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100027#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <asm/processor.h>
29#include <asm/pgtable.h>
30#include <asm/mmu.h>
31#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/cputable.h>
33#include <asm/rtas.h>
34#include <asm/sstep.h>
35#include <asm/bug.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100036
37#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100039#include <asm/paca.h>
40#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#include "nonstdio.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44#define scanhex xmon_scanhex
45#define skipbl xmon_skipbl
46
47#ifdef CONFIG_SMP
48cpumask_t cpus_in_xmon = CPU_MASK_NONE;
49static unsigned long xmon_taken = 1;
50static int xmon_owner;
51static int xmon_gate;
52#endif /* CONFIG_SMP */
53
54static unsigned long in_xmon = 0;
55
56static unsigned long adrs;
57static int size = 1;
58#define MAX_DUMP (128 * 1024)
59static unsigned long ndump = 64;
60static unsigned long nidump = 16;
61static unsigned long ncsum = 4096;
62static int termch;
63static char tmpstr[128];
64
Paul Mackerrasf78541d2005-10-28 22:53:37 +100065#define JMP_BUF_LEN 23
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static long bus_error_jmp[JMP_BUF_LEN];
67static int catch_memory_errors;
68static long *xmon_fault_jmp[NR_CPUS];
69#define setjmp xmon_setjmp
70#define longjmp xmon_longjmp
71
72/* Breakpoint stuff */
73struct bpt {
74 unsigned long address;
75 unsigned int instr[2];
76 atomic_t ref_count;
77 int enabled;
78 unsigned long pad;
79};
80
81/* Bits in bpt.enabled */
82#define BP_IABR_TE 1 /* IABR translation enabled */
83#define BP_IABR 2
84#define BP_TRAP 8
85#define BP_DABR 0x10
86
87#define NBPTS 256
88static struct bpt bpts[NBPTS];
89static struct bpt dabr;
90static struct bpt *iabr;
91static unsigned bpinstr = 0x7fe00008; /* trap */
92
93#define BP_NUM(bp) ((bp) - bpts + 1)
94
95/* Prototypes */
96static int cmds(struct pt_regs *);
97static int mread(unsigned long, void *, int);
98static int mwrite(unsigned long, void *, int);
99static int handle_fault(struct pt_regs *);
100static void byterev(unsigned char *, int);
101static void memex(void);
102static int bsesc(void);
103static void dump(void);
104static void prdump(unsigned long, long);
105static int ppc_inst_dump(unsigned long, long, int);
106void print_address(unsigned long);
107static void backtrace(struct pt_regs *);
108static void excprint(struct pt_regs *);
109static void prregs(struct pt_regs *);
110static void memops(int);
111static void memlocate(void);
112static void memzcan(void);
113static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
114int skipbl(void);
115int scanhex(unsigned long *valp);
116static void scannl(void);
117static int hexdigit(int);
118void getstring(char *, int);
119static void flush_input(void);
120static int inchar(void);
121static void take_input(char *);
122static unsigned long read_spr(int);
123static void write_spr(int, unsigned long);
124static void super_regs(void);
125static void remove_bpts(void);
126static void insert_bpts(void);
127static void remove_cpu_bpts(void);
128static void insert_cpu_bpts(void);
129static struct bpt *at_breakpoint(unsigned long pc);
130static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
131static int do_step(struct pt_regs *);
132static void bpt_cmds(void);
133static void cacheflush(void);
134static int cpu_cmd(void);
135static void csum(void);
136static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000137static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138void dump_segments(void);
139static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200140static void xmon_show_stack(unsigned long sp, unsigned long lr,
141 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static void xmon_print_symbol(unsigned long address, const char *mid,
143 const char *after);
144static const char *getvecname(unsigned long vec);
145
Olaf Hering26c8af52006-09-08 16:29:21 +0200146int xmon_no_auto_backtrace;
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148extern int print_insn_powerpc(unsigned long, unsigned long, int);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000149
150extern void xmon_enter(void);
151extern void xmon_leave(void);
152
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000153extern long setjmp(long *);
154extern void longjmp(long *, long);
155extern void xmon_save_regs(struct pt_regs *);
156
157#ifdef CONFIG_PPC64
158#define REG "%.16lx"
159#define REGS_PER_LINE 4
160#define LAST_VOLATILE 13
161#else
162#define REG "%.8lx"
163#define REGS_PER_LINE 8
164#define LAST_VOLATILE 12
165#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
168
169#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
170 || ('a' <= (c) && (c) <= 'f') \
171 || ('A' <= (c) && (c) <= 'F'))
172#define isalnum(c) (('0' <= (c) && (c) <= '9') \
173 || ('a' <= (c) && (c) <= 'z') \
174 || ('A' <= (c) && (c) <= 'Z'))
175#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
176
177static char *help_string = "\
178Commands:\n\
179 b show breakpoints\n\
180 bd set data breakpoint\n\
181 bi set instruction breakpoint\n\
182 bc clear breakpoint\n"
183#ifdef CONFIG_SMP
184 "\
185 c print cpus stopped in xmon\n\
186 c# try to switch to cpu number h (in hex)\n"
187#endif
188 "\
189 C checksum\n\
190 d dump bytes\n\
191 di dump instructions\n\
192 df dump float values\n\
193 dd dump double values\n\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100194 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 e print exception information\n\
196 f flush cache\n\
197 la lookup symbol+offset of specified address\n\
198 ls lookup address of specified symbol\n\
199 m examine/change memory\n\
200 mm move a block of memory\n\
201 ms set a block of memory\n\
202 md compare two blocks of memory\n\
203 ml locate a block of memory\n\
204 mz zero a block of memory\n\
205 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000206 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 r print registers\n\
208 s single step\n\
209 S print special registers\n\
210 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 x exit monitor and recover\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000212 X exit monitor and dont recover\n"
213#ifdef CONFIG_PPC64
214" u dump segment table or SLB\n"
215#endif
216#ifdef CONFIG_PPC_STD_MMU_32
217" u dump segment registers\n"
218#endif
219" ? help\n"
220" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 zh halt\n"
222;
223
224static struct pt_regs *xmon_regs;
225
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000226static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 asm volatile("sync; isync");
229}
230
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000231static inline void store_inst(void *p)
232{
233 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
234}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000236static inline void cflush(void *p)
237{
238 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
239}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000241static inline void cinval(void *p)
242{
243 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
244}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246/*
247 * Disable surveillance (the service processor watchdog function)
248 * while we are in xmon.
249 * XXX we should re-enable it when we leave. :)
250 */
251#define SURVEILLANCE_TOKEN 9000
252
253static inline void disable_surveillance(void)
254{
255#ifdef CONFIG_PPC_PSERIES
256 /* Since this can't be a module, args should end up below 4GB. */
257 static struct rtas_args args;
258
259 /*
260 * At this point we have got all the cpus we can into
261 * xmon, so there is hopefully no other cpu calling RTAS
262 * at the moment, even though we don't take rtas.lock.
263 * If we did try to take rtas.lock there would be a
264 * real possibility of deadlock.
265 */
266 args.token = rtas_token("set-indicator");
267 if (args.token == RTAS_UNKNOWN_SERVICE)
268 return;
269 args.nargs = 3;
270 args.nret = 1;
271 args.rets = &args.args[3];
272 args.args[0] = SURVEILLANCE_TOKEN;
273 args.args[1] = 0;
274 args.args[2] = 0;
275 enter_rtas(__pa(&args));
276#endif /* CONFIG_PPC_PSERIES */
277}
278
279#ifdef CONFIG_SMP
280static int xmon_speaker;
281
282static void get_output_lock(void)
283{
284 int me = smp_processor_id() + 0x100;
285 int last_speaker = 0, prev;
286 long timeout;
287
288 if (xmon_speaker == me)
289 return;
290 for (;;) {
291 if (xmon_speaker == 0) {
292 last_speaker = cmpxchg(&xmon_speaker, 0, me);
293 if (last_speaker == 0)
294 return;
295 }
296 timeout = 10000000;
297 while (xmon_speaker == last_speaker) {
298 if (--timeout > 0)
299 continue;
300 /* hostile takeover */
301 prev = cmpxchg(&xmon_speaker, last_speaker, me);
302 if (prev == last_speaker)
303 return;
304 break;
305 }
306 }
307}
308
309static void release_output_lock(void)
310{
311 xmon_speaker = 0;
312}
313#endif
314
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000315static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 int cmd = 0;
318 unsigned long msr;
319 struct bpt *bp;
320 long recurse_jmp[JMP_BUF_LEN];
321 unsigned long offset;
322#ifdef CONFIG_SMP
323 int cpu;
324 int secondary;
325 unsigned long timeout;
326#endif
327
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000328 msr = mfmsr();
329 mtmsr(msr & ~MSR_EE); /* disable interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 bp = in_breakpoint_table(regs->nip, &offset);
332 if (bp != NULL) {
333 regs->nip = bp->address + offset;
334 atomic_dec(&bp->ref_count);
335 }
336
337 remove_cpu_bpts();
338
339#ifdef CONFIG_SMP
340 cpu = smp_processor_id();
341 if (cpu_isset(cpu, cpus_in_xmon)) {
342 get_output_lock();
343 excprint(regs);
344 printf("cpu 0x%x: Exception %lx %s in xmon, "
345 "returning to main loop\n",
346 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000347 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 longjmp(xmon_fault_jmp[cpu], 1);
349 }
350
351 if (setjmp(recurse_jmp) != 0) {
352 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000353 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 printf("xmon: WARNING: bad recursive fault "
355 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000356 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 goto waiting;
358 }
359 secondary = !(xmon_taken && cpu == xmon_owner);
360 goto cmdloop;
361 }
362
363 xmon_fault_jmp[cpu] = recurse_jmp;
364 cpu_set(cpu, cpus_in_xmon);
365
366 bp = NULL;
367 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
368 bp = at_breakpoint(regs->nip);
369 if (bp || (regs->msr & MSR_RI) == 0)
370 fromipi = 0;
371
372 if (!fromipi) {
373 get_output_lock();
374 excprint(regs);
375 if (bp) {
376 printf("cpu 0x%x stopped at breakpoint 0x%x (",
377 cpu, BP_NUM(bp));
378 xmon_print_symbol(regs->nip, " ", ")\n");
379 }
380 if ((regs->msr & MSR_RI) == 0)
381 printf("WARNING: exception is not recoverable, "
382 "can't continue\n");
383 release_output_lock();
384 }
385
386 waiting:
387 secondary = 1;
388 while (secondary && !xmon_gate) {
389 if (in_xmon == 0) {
390 if (fromipi)
391 goto leave;
392 secondary = test_and_set_bit(0, &in_xmon);
393 }
394 barrier();
395 }
396
397 if (!secondary && !xmon_gate) {
398 /* we are the first cpu to come in */
399 /* interrupt other cpu(s) */
400 int ncpus = num_online_cpus();
401
402 xmon_owner = cpu;
403 mb();
404 if (ncpus > 1) {
405 smp_send_debugger_break(MSG_ALL_BUT_SELF);
406 /* wait for other cpus to come in */
407 for (timeout = 100000000; timeout != 0; --timeout) {
408 if (cpus_weight(cpus_in_xmon) >= ncpus)
409 break;
410 barrier();
411 }
412 }
413 remove_bpts();
414 disable_surveillance();
415 /* for breakpoint or single step, print the current instr. */
416 if (bp || TRAP(regs) == 0xd00)
417 ppc_inst_dump(regs->nip, 1, 0);
418 printf("enter ? for help\n");
419 mb();
420 xmon_gate = 1;
421 barrier();
422 }
423
424 cmdloop:
425 while (in_xmon) {
426 if (secondary) {
427 if (cpu == xmon_owner) {
428 if (!test_and_set_bit(0, &xmon_taken)) {
429 secondary = 0;
430 continue;
431 }
432 /* missed it */
433 while (cpu == xmon_owner)
434 barrier();
435 }
436 barrier();
437 } else {
438 cmd = cmds(regs);
439 if (cmd != 0) {
440 /* exiting xmon */
441 insert_bpts();
442 xmon_gate = 0;
443 wmb();
444 in_xmon = 0;
445 break;
446 }
447 /* have switched to some other cpu */
448 secondary = 1;
449 }
450 }
451 leave:
452 cpu_clear(cpu, cpus_in_xmon);
453 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454#else
455 /* UP is simple... */
456 if (in_xmon) {
457 printf("Exception %lx %s in xmon, returning to main loop\n",
458 regs->trap, getvecname(TRAP(regs)));
459 longjmp(xmon_fault_jmp[0], 1);
460 }
461 if (setjmp(recurse_jmp) == 0) {
462 xmon_fault_jmp[0] = recurse_jmp;
463 in_xmon = 1;
464
465 excprint(regs);
466 bp = at_breakpoint(regs->nip);
467 if (bp) {
468 printf("Stopped at breakpoint %x (", BP_NUM(bp));
469 xmon_print_symbol(regs->nip, " ", ")\n");
470 }
471 if ((regs->msr & MSR_RI) == 0)
472 printf("WARNING: exception is not recoverable, "
473 "can't continue\n");
474 remove_bpts();
475 disable_surveillance();
476 /* for breakpoint or single step, print the current instr. */
477 if (bp || TRAP(regs) == 0xd00)
478 ppc_inst_dump(regs->nip, 1, 0);
479 printf("enter ? for help\n");
480 }
481
482 cmd = cmds(regs);
483
484 insert_bpts();
485 in_xmon = 0;
486#endif
487
488 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
489 bp = at_breakpoint(regs->nip);
490 if (bp != NULL) {
491 int stepped = emulate_step(regs, bp->instr[0]);
492 if (stepped == 0) {
493 regs->nip = (unsigned long) &bp->instr[0];
494 atomic_inc(&bp->ref_count);
495 } else if (stepped < 0) {
496 printf("Couldn't single-step %s instruction\n",
497 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
498 }
499 }
500 }
501
502 insert_cpu_bpts();
503
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000504 mtmsr(msr); /* restore interrupt enable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
506 return cmd != 'X';
507}
508
509int xmon(struct pt_regs *excp)
510{
511 struct pt_regs regs;
512
513 if (excp == NULL) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000514 xmon_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 excp = &regs;
516 }
517 return xmon_core(excp, 0);
518}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000519EXPORT_SYMBOL(xmon);
520
521irqreturn_t
522xmon_irq(int irq, void *d, struct pt_regs *regs)
523{
524 unsigned long flags;
525 local_irq_save(flags);
526 printf("Keyboard interrupt\n");
527 xmon(regs);
528 local_irq_restore(flags);
529 return IRQ_HANDLED;
530}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000532static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533{
534 struct bpt *bp;
535 unsigned long offset;
536
537 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
538 return 0;
539
540 /* Are we at the trap at bp->instr[1] for some bp? */
541 bp = in_breakpoint_table(regs->nip, &offset);
542 if (bp != NULL && offset == 4) {
543 regs->nip = bp->address + 4;
544 atomic_dec(&bp->ref_count);
545 return 1;
546 }
547
548 /* Are we at a breakpoint? */
549 bp = at_breakpoint(regs->nip);
550 if (!bp)
551 return 0;
552
553 xmon_core(regs, 0);
554
555 return 1;
556}
557
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000558static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559{
560 if (user_mode(regs))
561 return 0;
562 xmon_core(regs, 0);
563 return 1;
564}
565
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000566static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
568 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
569 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000570 if (dabr.enabled == 0)
571 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 xmon_core(regs, 0);
573 return 1;
574}
575
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000576static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
579 return 0;
580 if (iabr == 0)
581 return 0;
582 xmon_core(regs, 0);
583 return 1;
584}
585
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000586static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
588#ifdef CONFIG_SMP
589 if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
590 xmon_core(regs, 1);
591#endif
592 return 0;
593}
594
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000595static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
597 struct bpt *bp;
598 unsigned long offset;
599
600 if (in_xmon && catch_memory_errors)
601 handle_fault(regs); /* doesn't return */
602
603 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
604 bp = in_breakpoint_table(regs->nip, &offset);
605 if (bp != NULL) {
606 regs->nip = bp->address + offset;
607 atomic_dec(&bp->ref_count);
608 }
609 }
610
611 return 0;
612}
613
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614static struct bpt *at_breakpoint(unsigned long pc)
615{
616 int i;
617 struct bpt *bp;
618
619 bp = bpts;
620 for (i = 0; i < NBPTS; ++i, ++bp)
621 if (bp->enabled && pc == bp->address)
622 return bp;
623 return NULL;
624}
625
626static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
627{
628 unsigned long off;
629
630 off = nip - (unsigned long) bpts;
631 if (off >= sizeof(bpts))
632 return NULL;
633 off %= sizeof(struct bpt);
634 if (off != offsetof(struct bpt, instr[0])
635 && off != offsetof(struct bpt, instr[1]))
636 return NULL;
637 *offp = off - offsetof(struct bpt, instr[0]);
638 return (struct bpt *) (nip - off);
639}
640
641static struct bpt *new_breakpoint(unsigned long a)
642{
643 struct bpt *bp;
644
645 a &= ~3UL;
646 bp = at_breakpoint(a);
647 if (bp)
648 return bp;
649
650 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
651 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
652 bp->address = a;
653 bp->instr[1] = bpinstr;
654 store_inst(&bp->instr[1]);
655 return bp;
656 }
657 }
658
659 printf("Sorry, no free breakpoints. Please clear one first.\n");
660 return NULL;
661}
662
663static void insert_bpts(void)
664{
665 int i;
666 struct bpt *bp;
667
668 bp = bpts;
669 for (i = 0; i < NBPTS; ++i, ++bp) {
670 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
671 continue;
672 if (mread(bp->address, &bp->instr[0], 4) != 4) {
673 printf("Couldn't read instruction at %lx, "
674 "disabling breakpoint there\n", bp->address);
675 bp->enabled = 0;
676 continue;
677 }
678 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
679 printf("Breakpoint at %lx is on an mtmsrd or rfid "
680 "instruction, disabling it\n", bp->address);
681 bp->enabled = 0;
682 continue;
683 }
684 store_inst(&bp->instr[0]);
685 if (bp->enabled & BP_IABR)
686 continue;
687 if (mwrite(bp->address, &bpinstr, 4) != 4) {
688 printf("Couldn't write instruction at %lx, "
689 "disabling breakpoint there\n", bp->address);
690 bp->enabled &= ~BP_TRAP;
691 continue;
692 }
693 store_inst((void *)bp->address);
694 }
695}
696
697static void insert_cpu_bpts(void)
698{
699 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000700 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000702 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
704}
705
706static void remove_bpts(void)
707{
708 int i;
709 struct bpt *bp;
710 unsigned instr;
711
712 bp = bpts;
713 for (i = 0; i < NBPTS; ++i, ++bp) {
714 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
715 continue;
716 if (mread(bp->address, &instr, 4) == 4
717 && instr == bpinstr
718 && mwrite(bp->address, &bp->instr, 4) != 4)
719 printf("Couldn't remove breakpoint at %lx\n",
720 bp->address);
721 else
722 store_inst((void *)bp->address);
723 }
724}
725
726static void remove_cpu_bpts(void)
727{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000728 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000730 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
733/* Command interpreting routine */
734static char *last_cmd;
735
736static int
737cmds(struct pt_regs *excp)
738{
739 int cmd = 0;
740
741 last_cmd = NULL;
742 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200743
744 if (!xmon_no_auto_backtrace) {
745 xmon_no_auto_backtrace = 1;
746 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
747 }
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 for(;;) {
750#ifdef CONFIG_SMP
751 printf("%x:", smp_processor_id());
752#endif /* CONFIG_SMP */
753 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 flush_input();
755 termch = 0;
756 cmd = skipbl();
757 if( cmd == '\n' ) {
758 if (last_cmd == NULL)
759 continue;
760 take_input(last_cmd);
761 last_cmd = NULL;
762 cmd = inchar();
763 }
764 switch (cmd) {
765 case 'm':
766 cmd = inchar();
767 switch (cmd) {
768 case 'm':
769 case 's':
770 case 'd':
771 memops(cmd);
772 break;
773 case 'l':
774 memlocate();
775 break;
776 case 'z':
777 memzcan();
778 break;
779 case 'i':
780 show_mem();
781 break;
782 default:
783 termch = cmd;
784 memex();
785 }
786 break;
787 case 'd':
788 dump();
789 break;
790 case 'l':
791 symbol_lookup();
792 break;
793 case 'r':
794 prregs(excp); /* print regs */
795 break;
796 case 'e':
797 excprint(excp);
798 break;
799 case 'S':
800 super_regs();
801 break;
802 case 't':
803 backtrace(excp);
804 break;
805 case 'f':
806 cacheflush();
807 break;
808 case 's':
809 if (do_step(excp))
810 return cmd;
811 break;
812 case 'x':
813 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100814 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100816 printf(" <no input ...>\n");
817 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 return cmd;
819 case '?':
820 printf(help_string);
821 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 case 'b':
823 bpt_cmds();
824 break;
825 case 'C':
826 csum();
827 break;
828 case 'c':
829 if (cpu_cmd())
830 return 0;
831 break;
832 case 'z':
833 bootcmds();
834 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000835 case 'p':
836 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000838#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 case 'u':
840 dump_segments();
841 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000842#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 default:
844 printf("Unrecognized command: ");
845 do {
846 if (' ' < cmd && cmd <= '~')
847 putchar(cmd);
848 else
849 printf("\\x%x", cmd);
850 cmd = inchar();
851 } while (cmd != '\n');
852 printf(" (type ? for help)\n");
853 break;
854 }
855 }
856}
857
858/*
859 * Step a single instruction.
860 * Some instructions we emulate, others we execute with MSR_SE set.
861 */
862static int do_step(struct pt_regs *regs)
863{
864 unsigned int instr;
865 int stepped;
866
867 /* check we are in 64-bit kernel mode, translation enabled */
868 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
869 if (mread(regs->nip, &instr, 4) == 4) {
870 stepped = emulate_step(regs, instr);
871 if (stepped < 0) {
872 printf("Couldn't single-step %s instruction\n",
873 (IS_RFID(instr)? "rfid": "mtmsrd"));
874 return 0;
875 }
876 if (stepped > 0) {
877 regs->trap = 0xd00 | (regs->trap & 1);
878 printf("stepped to ");
879 xmon_print_symbol(regs->nip, " ", "\n");
880 ppc_inst_dump(regs->nip, 1, 0);
881 return 0;
882 }
883 }
884 }
885 regs->msr |= MSR_SE;
886 return 1;
887}
888
889static void bootcmds(void)
890{
891 int cmd;
892
893 cmd = inchar();
894 if (cmd == 'r')
895 ppc_md.restart(NULL);
896 else if (cmd == 'h')
897 ppc_md.halt();
898 else if (cmd == 'p')
899 ppc_md.power_off();
900}
901
902static int cpu_cmd(void)
903{
904#ifdef CONFIG_SMP
905 unsigned long cpu;
906 int timeout;
907 int count;
908
909 if (!scanhex(&cpu)) {
910 /* print cpus waiting or in xmon */
911 printf("cpus stopped:");
912 count = 0;
913 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
914 if (cpu_isset(cpu, cpus_in_xmon)) {
915 if (count == 0)
916 printf(" %x", cpu);
917 ++count;
918 } else {
919 if (count > 1)
920 printf("-%x", cpu - 1);
921 count = 0;
922 }
923 }
924 if (count > 1)
925 printf("-%x", NR_CPUS - 1);
926 printf("\n");
927 return 0;
928 }
929 /* try to switch to cpu specified */
930 if (!cpu_isset(cpu, cpus_in_xmon)) {
931 printf("cpu 0x%x isn't in xmon\n", cpu);
932 return 0;
933 }
934 xmon_taken = 0;
935 mb();
936 xmon_owner = cpu;
937 timeout = 10000000;
938 while (!xmon_taken) {
939 if (--timeout == 0) {
940 if (test_and_set_bit(0, &xmon_taken))
941 break;
942 /* take control back */
943 mb();
944 xmon_owner = smp_processor_id();
945 printf("cpu %u didn't take control\n", cpu);
946 return 0;
947 }
948 barrier();
949 }
950 return 1;
951#else
952 return 0;
953#endif /* CONFIG_SMP */
954}
955
956static unsigned short fcstab[256] = {
957 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
958 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
959 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
960 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
961 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
962 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
963 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
964 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
965 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
966 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
967 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
968 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
969 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
970 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
971 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
972 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
973 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
974 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
975 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
976 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
977 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
978 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
979 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
980 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
981 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
982 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
983 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
984 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
985 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
986 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
987 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
988 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
989};
990
991#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
992
993static void
994csum(void)
995{
996 unsigned int i;
997 unsigned short fcs;
998 unsigned char v;
999
1000 if (!scanhex(&adrs))
1001 return;
1002 if (!scanhex(&ncsum))
1003 return;
1004 fcs = 0xffff;
1005 for (i = 0; i < ncsum; ++i) {
1006 if (mread(adrs+i, &v, 1) == 0) {
1007 printf("csum stopped at %x\n", adrs+i);
1008 break;
1009 }
1010 fcs = FCS(fcs, v);
1011 }
1012 printf("%x\n", fcs);
1013}
1014
1015/*
1016 * Check if this is a suitable place to put a breakpoint.
1017 */
1018static long check_bp_loc(unsigned long addr)
1019{
1020 unsigned int instr;
1021
1022 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001023 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 printf("Breakpoints may only be placed at kernel addresses\n");
1025 return 0;
1026 }
1027 if (!mread(addr, &instr, sizeof(instr))) {
1028 printf("Can't read instruction at address %lx\n", addr);
1029 return 0;
1030 }
1031 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1032 printf("Breakpoints may not be placed on mtmsrd or rfid "
1033 "instructions\n");
1034 return 0;
1035 }
1036 return 1;
1037}
1038
1039static char *breakpoint_help_string =
1040 "Breakpoint command usage:\n"
1041 "b show breakpoints\n"
1042 "b <addr> [cnt] set breakpoint at given instr addr\n"
1043 "bc clear all breakpoints\n"
1044 "bc <n/addr> clear breakpoint number n or at addr\n"
1045 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1046 "bd <addr> [cnt] set hardware data breakpoint\n"
1047 "";
1048
1049static void
1050bpt_cmds(void)
1051{
1052 int cmd;
1053 unsigned long a;
1054 int mode, i;
1055 struct bpt *bp;
1056 const char badaddr[] = "Only kernel addresses are permitted "
1057 "for breakpoints\n";
1058
1059 cmd = inchar();
1060 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001061#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 case 'd': /* bd - hardware data breakpoint */
1063 mode = 7;
1064 cmd = inchar();
1065 if (cmd == 'r')
1066 mode = 5;
1067 else if (cmd == 'w')
1068 mode = 6;
1069 else
1070 termch = cmd;
1071 dabr.address = 0;
1072 dabr.enabled = 0;
1073 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001074 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 printf(badaddr);
1076 break;
1077 }
1078 dabr.address &= ~7;
1079 dabr.enabled = mode | BP_DABR;
1080 }
1081 break;
1082
1083 case 'i': /* bi - hardware instr breakpoint */
1084 if (!cpu_has_feature(CPU_FTR_IABR)) {
1085 printf("Hardware instruction breakpoint "
1086 "not supported on this cpu\n");
1087 break;
1088 }
1089 if (iabr) {
1090 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1091 iabr = NULL;
1092 }
1093 if (!scanhex(&a))
1094 break;
1095 if (!check_bp_loc(a))
1096 break;
1097 bp = new_breakpoint(a);
1098 if (bp != NULL) {
1099 bp->enabled |= BP_IABR | BP_IABR_TE;
1100 iabr = bp;
1101 }
1102 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001103#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 case 'c':
1106 if (!scanhex(&a)) {
1107 /* clear all breakpoints */
1108 for (i = 0; i < NBPTS; ++i)
1109 bpts[i].enabled = 0;
1110 iabr = NULL;
1111 dabr.enabled = 0;
1112 printf("All breakpoints cleared\n");
1113 break;
1114 }
1115
1116 if (a <= NBPTS && a >= 1) {
1117 /* assume a breakpoint number */
1118 bp = &bpts[a-1]; /* bp nums are 1 based */
1119 } else {
1120 /* assume a breakpoint address */
1121 bp = at_breakpoint(a);
1122 if (bp == 0) {
1123 printf("No breakpoint at %x\n", a);
1124 break;
1125 }
1126 }
1127
1128 printf("Cleared breakpoint %x (", BP_NUM(bp));
1129 xmon_print_symbol(bp->address, " ", ")\n");
1130 bp->enabled = 0;
1131 break;
1132
1133 default:
1134 termch = cmd;
1135 cmd = skipbl();
1136 if (cmd == '?') {
1137 printf(breakpoint_help_string);
1138 break;
1139 }
1140 termch = cmd;
1141 if (!scanhex(&a)) {
1142 /* print all breakpoints */
1143 printf(" type address\n");
1144 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001145 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (dabr.enabled & 1)
1147 printf("r");
1148 if (dabr.enabled & 2)
1149 printf("w");
1150 printf("]\n");
1151 }
1152 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1153 if (!bp->enabled)
1154 continue;
1155 printf("%2x %s ", BP_NUM(bp),
1156 (bp->enabled & BP_IABR)? "inst": "trap");
1157 xmon_print_symbol(bp->address, " ", "\n");
1158 }
1159 break;
1160 }
1161
1162 if (!check_bp_loc(a))
1163 break;
1164 bp = new_breakpoint(a);
1165 if (bp != NULL)
1166 bp->enabled |= BP_TRAP;
1167 break;
1168 }
1169}
1170
1171/* Very cheap human name for vector lookup. */
1172static
1173const char *getvecname(unsigned long vec)
1174{
1175 char *ret;
1176
1177 switch (vec) {
1178 case 0x100: ret = "(System Reset)"; break;
1179 case 0x200: ret = "(Machine Check)"; break;
1180 case 0x300: ret = "(Data Access)"; break;
1181 case 0x380: ret = "(Data SLB Access)"; break;
1182 case 0x400: ret = "(Instruction Access)"; break;
1183 case 0x480: ret = "(Instruction SLB Access)"; break;
1184 case 0x500: ret = "(Hardware Interrupt)"; break;
1185 case 0x600: ret = "(Alignment)"; break;
1186 case 0x700: ret = "(Program Check)"; break;
1187 case 0x800: ret = "(FPU Unavailable)"; break;
1188 case 0x900: ret = "(Decrementer)"; break;
1189 case 0xc00: ret = "(System Call)"; break;
1190 case 0xd00: ret = "(Single Step)"; break;
1191 case 0xf00: ret = "(Performance Monitor)"; break;
1192 case 0xf20: ret = "(Altivec Unavailable)"; break;
1193 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1194 default: ret = "";
1195 }
1196 return ret;
1197}
1198
1199static void get_function_bounds(unsigned long pc, unsigned long *startp,
1200 unsigned long *endp)
1201{
1202 unsigned long size, offset;
1203 const char *name;
1204 char *modname;
1205
1206 *startp = *endp = 0;
1207 if (pc == 0)
1208 return;
1209 if (setjmp(bus_error_jmp) == 0) {
1210 catch_memory_errors = 1;
1211 sync();
1212 name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
1213 if (name != NULL) {
1214 *startp = pc - offset;
1215 *endp = pc - offset + size;
1216 }
1217 sync();
1218 }
1219 catch_memory_errors = 0;
1220}
1221
1222static int xmon_depth_to_print = 64;
1223
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001224#ifdef CONFIG_PPC64
1225#define LRSAVE_OFFSET 0x10
1226#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1227#define MARKER_OFFSET 0x60
1228#define REGS_OFFSET 0x70
1229#else
1230#define LRSAVE_OFFSET 4
1231#define REG_FRAME_MARKER 0x72656773
1232#define MARKER_OFFSET 8
1233#define REGS_OFFSET 16
1234#endif
1235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236static void xmon_show_stack(unsigned long sp, unsigned long lr,
1237 unsigned long pc)
1238{
1239 unsigned long ip;
1240 unsigned long newsp;
1241 unsigned long marker;
1242 int count = 0;
1243 struct pt_regs regs;
1244
1245 do {
1246 if (sp < PAGE_OFFSET) {
1247 if (sp != 0)
1248 printf("SP (%lx) is in userspace\n", sp);
1249 break;
1250 }
1251
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001252 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 || !mread(sp, &newsp, sizeof(unsigned long))) {
1254 printf("Couldn't read stack frame at %lx\n", sp);
1255 break;
1256 }
1257
1258 /*
1259 * For the first stack frame, try to work out if
1260 * LR and/or the saved LR value in the bottommost
1261 * stack frame are valid.
1262 */
1263 if ((pc | lr) != 0) {
1264 unsigned long fnstart, fnend;
1265 unsigned long nextip;
1266 int printip = 1;
1267
1268 get_function_bounds(pc, &fnstart, &fnend);
1269 nextip = 0;
1270 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001271 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 sizeof(unsigned long));
1273 if (lr == ip) {
1274 if (lr < PAGE_OFFSET
1275 || (fnstart <= lr && lr < fnend))
1276 printip = 0;
1277 } else if (lr == nextip) {
1278 printip = 0;
1279 } else if (lr >= PAGE_OFFSET
1280 && !(fnstart <= lr && lr < fnend)) {
1281 printf("[link register ] ");
1282 xmon_print_symbol(lr, " ", "\n");
1283 }
1284 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001285 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 xmon_print_symbol(ip, " ", " (unreliable)\n");
1287 }
1288 pc = lr = 0;
1289
1290 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001291 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 xmon_print_symbol(ip, " ", "\n");
1293 }
1294
1295 /* Look for "regshere" marker to see if this is
1296 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001297 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1298 && marker == REG_FRAME_MARKER) {
1299 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 != sizeof(regs)) {
1301 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001302 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 break;
1304 }
1305 printf("--- Exception: %lx %s at ", regs.trap,
1306 getvecname(TRAP(&regs)));
1307 pc = regs.nip;
1308 lr = regs.link;
1309 xmon_print_symbol(pc, " ", "\n");
1310 }
1311
1312 if (newsp == 0)
1313 break;
1314
1315 sp = newsp;
1316 } while (count++ < xmon_depth_to_print);
1317}
1318
1319static void backtrace(struct pt_regs *excp)
1320{
1321 unsigned long sp;
1322
1323 if (scanhex(&sp))
1324 xmon_show_stack(sp, 0, 0);
1325 else
1326 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1327 scannl();
1328}
1329
1330static void print_bug_trap(struct pt_regs *regs)
1331{
1332 struct bug_entry *bug;
1333 unsigned long addr;
1334
1335 if (regs->msr & MSR_PR)
1336 return; /* not in kernel */
1337 addr = regs->nip; /* address of trap instruction */
1338 if (addr < PAGE_OFFSET)
1339 return;
1340 bug = find_bug(regs->nip);
1341 if (bug == NULL)
1342 return;
1343 if (bug->line & BUG_WARNING_TRAP)
1344 return;
1345
1346 printf("kernel BUG in %s at %s:%d!\n",
1347 bug->function, bug->file, (unsigned int)bug->line);
1348}
1349
1350void excprint(struct pt_regs *fp)
1351{
1352 unsigned long trap;
1353
1354#ifdef CONFIG_SMP
1355 printf("cpu 0x%x: ", smp_processor_id());
1356#endif /* CONFIG_SMP */
1357
1358 trap = TRAP(fp);
1359 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1360 printf(" pc: ");
1361 xmon_print_symbol(fp->nip, ": ", "\n");
1362
1363 printf(" lr: ", fp->link);
1364 xmon_print_symbol(fp->link, ": ", "\n");
1365
1366 printf(" sp: %lx\n", fp->gpr[1]);
1367 printf(" msr: %lx\n", fp->msr);
1368
1369 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1370 printf(" dar: %lx\n", fp->dar);
1371 if (trap != 0x380)
1372 printf(" dsisr: %lx\n", fp->dsisr);
1373 }
1374
1375 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001376#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001378#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 if (current) {
1380 printf(" pid = %ld, comm = %s\n",
1381 current->pid, current->comm);
1382 }
1383
1384 if (trap == 0x700)
1385 print_bug_trap(fp);
1386}
1387
1388void prregs(struct pt_regs *fp)
1389{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001390 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 unsigned long base;
1392 struct pt_regs regs;
1393
1394 if (scanhex(&base)) {
1395 if (setjmp(bus_error_jmp) == 0) {
1396 catch_memory_errors = 1;
1397 sync();
1398 regs = *(struct pt_regs *)base;
1399 sync();
1400 __delay(200);
1401 } else {
1402 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001403 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 base);
1405 return;
1406 }
1407 catch_memory_errors = 0;
1408 fp = &regs;
1409 }
1410
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001411#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 if (FULL_REGS(fp)) {
1413 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001414 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1416 } else {
1417 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001418 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1420 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001421#else
1422 for (n = 0; n < 32; ++n) {
1423 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1424 (n & 3) == 3? "\n": " ");
1425 if (n == 12 && !FULL_REGS(fp)) {
1426 printf("\n");
1427 break;
1428 }
1429 }
1430#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 printf("pc = ");
1432 xmon_print_symbol(fp->nip, " ", "\n");
1433 printf("lr = ");
1434 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001435 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1436 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001438 trap = TRAP(fp);
1439 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1440 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441}
1442
1443void cacheflush(void)
1444{
1445 int cmd;
1446 unsigned long nflush;
1447
1448 cmd = inchar();
1449 if (cmd != 'i')
1450 termch = cmd;
1451 scanhex((void *)&adrs);
1452 if (termch != '\n')
1453 termch = 0;
1454 nflush = 1;
1455 scanhex(&nflush);
1456 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1457 if (setjmp(bus_error_jmp) == 0) {
1458 catch_memory_errors = 1;
1459 sync();
1460
1461 if (cmd != 'i') {
1462 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1463 cflush((void *) adrs);
1464 } else {
1465 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1466 cinval((void *) adrs);
1467 }
1468 sync();
1469 /* wait a little while to see if we get a machine check */
1470 __delay(200);
1471 }
1472 catch_memory_errors = 0;
1473}
1474
1475unsigned long
1476read_spr(int n)
1477{
1478 unsigned int instrs[2];
1479 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001481#ifdef CONFIG_PPC64
1482 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 opd[0] = (unsigned long)instrs;
1485 opd[1] = 0;
1486 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001487 code = (unsigned long (*)(void)) opd;
1488#else
1489 code = (unsigned long (*)(void)) instrs;
1490#endif
1491
1492 /* mfspr r3,n; blr */
1493 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1494 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 store_inst(instrs);
1496 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
1498 if (setjmp(bus_error_jmp) == 0) {
1499 catch_memory_errors = 1;
1500 sync();
1501
1502 ret = code();
1503
1504 sync();
1505 /* wait a little while to see if we get a machine check */
1506 __delay(200);
1507 n = size;
1508 }
1509
1510 return ret;
1511}
1512
1513void
1514write_spr(int n, unsigned long val)
1515{
1516 unsigned int instrs[2];
1517 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001518#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 unsigned long opd[3];
1520
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 opd[0] = (unsigned long)instrs;
1522 opd[1] = 0;
1523 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001524 code = (unsigned long (*)(unsigned long)) opd;
1525#else
1526 code = (unsigned long (*)(unsigned long)) instrs;
1527#endif
1528
1529 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1530 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 store_inst(instrs);
1532 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
1534 if (setjmp(bus_error_jmp) == 0) {
1535 catch_memory_errors = 1;
1536 sync();
1537
1538 code(val);
1539
1540 sync();
1541 /* wait a little while to see if we get a machine check */
1542 __delay(200);
1543 n = size;
1544 }
1545}
1546
1547static unsigned long regno;
1548extern char exc_prolog;
1549extern char dec_exc;
1550
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001551void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552{
1553 int cmd;
1554 unsigned long val;
1555#ifdef CONFIG_PPC_ISERIES
1556 struct paca_struct *ptrPaca = NULL;
1557 struct lppaca *ptrLpPaca = NULL;
1558 struct ItLpRegSave *ptrLpRegSave = NULL;
1559#endif
1560
1561 cmd = skipbl();
1562 if (cmd == '\n') {
1563 unsigned long sp, toc;
1564 asm("mr %0,1" : "=r" (sp) :);
1565 asm("mr %0,2" : "=r" (toc) :);
1566
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001567 printf("msr = "REG" sprg0= "REG"\n",
1568 mfmsr(), mfspr(SPRN_SPRG0));
1569 printf("pvr = "REG" sprg1= "REG"\n",
1570 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1571 printf("dec = "REG" sprg2= "REG"\n",
1572 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1573 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1574 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575#ifdef CONFIG_PPC_ISERIES
1576 // Dump out relevant Paca data areas.
1577 printf("Paca: \n");
1578 ptrPaca = get_paca();
1579
1580 printf(" Local Processor Control Area (LpPaca): \n");
1581 ptrLpPaca = ptrPaca->lppaca_ptr;
1582 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1583 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1584 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1585 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1586 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1587
1588 printf(" Local Processor Register Save Area (LpRegSave): \n");
1589 ptrLpRegSave = ptrPaca->reg_save_ptr;
1590 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1591 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1592 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1593 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1594 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1595 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1596#endif
1597
1598 return;
1599 }
1600
1601 scanhex(&regno);
1602 switch (cmd) {
1603 case 'w':
1604 val = read_spr(regno);
1605 scanhex(&val);
1606 write_spr(regno, val);
1607 /* fall through */
1608 case 'r':
1609 printf("spr %lx = %lx\n", regno, read_spr(regno));
1610 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 }
1612 scannl();
1613}
1614
1615/*
1616 * Stuff for reading and writing memory safely
1617 */
1618int
1619mread(unsigned long adrs, void *buf, int size)
1620{
1621 volatile int n;
1622 char *p, *q;
1623
1624 n = 0;
1625 if (setjmp(bus_error_jmp) == 0) {
1626 catch_memory_errors = 1;
1627 sync();
1628 p = (char *)adrs;
1629 q = (char *)buf;
1630 switch (size) {
1631 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001632 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 break;
1634 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001635 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 break;
1637 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001638 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 break;
1640 default:
1641 for( ; n < size; ++n) {
1642 *q++ = *p++;
1643 sync();
1644 }
1645 }
1646 sync();
1647 /* wait a little while to see if we get a machine check */
1648 __delay(200);
1649 n = size;
1650 }
1651 catch_memory_errors = 0;
1652 return n;
1653}
1654
1655int
1656mwrite(unsigned long adrs, void *buf, int size)
1657{
1658 volatile int n;
1659 char *p, *q;
1660
1661 n = 0;
1662 if (setjmp(bus_error_jmp) == 0) {
1663 catch_memory_errors = 1;
1664 sync();
1665 p = (char *) adrs;
1666 q = (char *) buf;
1667 switch (size) {
1668 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001669 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 break;
1671 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001672 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 break;
1674 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001675 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 break;
1677 default:
1678 for ( ; n < size; ++n) {
1679 *p++ = *q++;
1680 sync();
1681 }
1682 }
1683 sync();
1684 /* wait a little while to see if we get a machine check */
1685 __delay(200);
1686 n = size;
1687 } else {
1688 printf("*** Error writing address %x\n", adrs + n);
1689 }
1690 catch_memory_errors = 0;
1691 return n;
1692}
1693
1694static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001695static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696static char *fault_chars[] = { "--", "**", "##" };
1697
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001698static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001700 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 switch (TRAP(regs)) {
1702 case 0x200:
1703 fault_type = 0;
1704 break;
1705 case 0x300:
1706 case 0x380:
1707 fault_type = 1;
1708 break;
1709 default:
1710 fault_type = 2;
1711 }
1712
1713 longjmp(bus_error_jmp, 1);
1714
1715 return 0;
1716}
1717
1718#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1719
1720void
1721byterev(unsigned char *val, int size)
1722{
1723 int t;
1724
1725 switch (size) {
1726 case 2:
1727 SWAP(val[0], val[1], t);
1728 break;
1729 case 4:
1730 SWAP(val[0], val[3], t);
1731 SWAP(val[1], val[2], t);
1732 break;
1733 case 8: /* is there really any use for this? */
1734 SWAP(val[0], val[7], t);
1735 SWAP(val[1], val[6], t);
1736 SWAP(val[2], val[5], t);
1737 SWAP(val[3], val[4], t);
1738 break;
1739 }
1740}
1741
1742static int brev;
1743static int mnoread;
1744
1745static char *memex_help_string =
1746 "Memory examine command usage:\n"
1747 "m [addr] [flags] examine/change memory\n"
1748 " addr is optional. will start where left off.\n"
1749 " flags may include chars from this set:\n"
1750 " b modify by bytes (default)\n"
1751 " w modify by words (2 byte)\n"
1752 " l modify by longs (4 byte)\n"
1753 " d modify by doubleword (8 byte)\n"
1754 " r toggle reverse byte order mode\n"
1755 " n do not read memory (for i/o spaces)\n"
1756 " . ok to read (default)\n"
1757 "NOTE: flags are saved as defaults\n"
1758 "";
1759
1760static char *memex_subcmd_help_string =
1761 "Memory examine subcommands:\n"
1762 " hexval write this val to current location\n"
1763 " 'string' write chars from string to this location\n"
1764 " ' increment address\n"
1765 " ^ decrement address\n"
1766 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1767 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1768 " ` clear no-read flag\n"
1769 " ; stay at this addr\n"
1770 " v change to byte mode\n"
1771 " w change to word (2 byte) mode\n"
1772 " l change to long (4 byte) mode\n"
1773 " u change to doubleword (8 byte) mode\n"
1774 " m addr change current addr\n"
1775 " n toggle no-read flag\n"
1776 " r toggle byte reverse flag\n"
1777 " < count back up count bytes\n"
1778 " > count skip forward count bytes\n"
1779 " x exit this mode\n"
1780 "";
1781
1782void
1783memex(void)
1784{
1785 int cmd, inc, i, nslash;
1786 unsigned long n;
1787 unsigned char val[16];
1788
1789 scanhex((void *)&adrs);
1790 cmd = skipbl();
1791 if (cmd == '?') {
1792 printf(memex_help_string);
1793 return;
1794 } else {
1795 termch = cmd;
1796 }
1797 last_cmd = "m\n";
1798 while ((cmd = skipbl()) != '\n') {
1799 switch( cmd ){
1800 case 'b': size = 1; break;
1801 case 'w': size = 2; break;
1802 case 'l': size = 4; break;
1803 case 'd': size = 8; break;
1804 case 'r': brev = !brev; break;
1805 case 'n': mnoread = 1; break;
1806 case '.': mnoread = 0; break;
1807 }
1808 }
1809 if( size <= 0 )
1810 size = 1;
1811 else if( size > 8 )
1812 size = 8;
1813 for(;;){
1814 if (!mnoread)
1815 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001816 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 if (!mnoread) {
1818 if (brev)
1819 byterev(val, size);
1820 putchar(' ');
1821 for (i = 0; i < n; ++i)
1822 printf("%.2x", val[i]);
1823 for (; i < size; ++i)
1824 printf("%s", fault_chars[fault_type]);
1825 }
1826 putchar(' ');
1827 inc = size;
1828 nslash = 0;
1829 for(;;){
1830 if( scanhex(&n) ){
1831 for (i = 0; i < size; ++i)
1832 val[i] = n >> (i * 8);
1833 if (!brev)
1834 byterev(val, size);
1835 mwrite(adrs, val, size);
1836 inc = size;
1837 }
1838 cmd = skipbl();
1839 if (cmd == '\n')
1840 break;
1841 inc = 0;
1842 switch (cmd) {
1843 case '\'':
1844 for(;;){
1845 n = inchar();
1846 if( n == '\\' )
1847 n = bsesc();
1848 else if( n == '\'' )
1849 break;
1850 for (i = 0; i < size; ++i)
1851 val[i] = n >> (i * 8);
1852 if (!brev)
1853 byterev(val, size);
1854 mwrite(adrs, val, size);
1855 adrs += size;
1856 }
1857 adrs -= size;
1858 inc = size;
1859 break;
1860 case ',':
1861 adrs += size;
1862 break;
1863 case '.':
1864 mnoread = 0;
1865 break;
1866 case ';':
1867 break;
1868 case 'x':
1869 case EOF:
1870 scannl();
1871 return;
1872 case 'b':
1873 case 'v':
1874 size = 1;
1875 break;
1876 case 'w':
1877 size = 2;
1878 break;
1879 case 'l':
1880 size = 4;
1881 break;
1882 case 'u':
1883 size = 8;
1884 break;
1885 case '^':
1886 adrs -= size;
1887 break;
1888 break;
1889 case '/':
1890 if (nslash > 0)
1891 adrs -= 1 << nslash;
1892 else
1893 nslash = 0;
1894 nslash += 4;
1895 adrs += 1 << nslash;
1896 break;
1897 case '\\':
1898 if (nslash < 0)
1899 adrs += 1 << -nslash;
1900 else
1901 nslash = 0;
1902 nslash -= 4;
1903 adrs -= 1 << -nslash;
1904 break;
1905 case 'm':
1906 scanhex((void *)&adrs);
1907 break;
1908 case 'n':
1909 mnoread = 1;
1910 break;
1911 case 'r':
1912 brev = !brev;
1913 break;
1914 case '<':
1915 n = size;
1916 scanhex(&n);
1917 adrs -= n;
1918 break;
1919 case '>':
1920 n = size;
1921 scanhex(&n);
1922 adrs += n;
1923 break;
1924 case '?':
1925 printf(memex_subcmd_help_string);
1926 break;
1927 }
1928 }
1929 adrs += inc;
1930 }
1931}
1932
1933int
1934bsesc(void)
1935{
1936 int c;
1937
1938 c = inchar();
1939 switch( c ){
1940 case 'n': c = '\n'; break;
1941 case 'r': c = '\r'; break;
1942 case 'b': c = '\b'; break;
1943 case 't': c = '\t'; break;
1944 }
1945 return c;
1946}
1947
Olaf Hering7e5b5932006-03-08 20:40:28 +01001948static void xmon_rawdump (unsigned long adrs, long ndump)
1949{
1950 long n, m, r, nr;
1951 unsigned char temp[16];
1952
1953 for (n = ndump; n > 0;) {
1954 r = n < 16? n: 16;
1955 nr = mread(adrs, temp, r);
1956 adrs += nr;
1957 for (m = 0; m < r; ++m) {
1958 if (m < nr)
1959 printf("%.2x", temp[m]);
1960 else
1961 printf("%s", fault_chars[fault_type]);
1962 }
1963 n -= r;
1964 if (nr < r)
1965 break;
1966 }
1967 printf("\n");
1968}
1969
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
1971 || ('a' <= (c) && (c) <= 'f') \
1972 || ('A' <= (c) && (c) <= 'F'))
1973void
1974dump(void)
1975{
1976 int c;
1977
1978 c = inchar();
1979 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1980 termch = c;
1981 scanhex((void *)&adrs);
1982 if (termch != '\n')
1983 termch = 0;
1984 if (c == 'i') {
1985 scanhex(&nidump);
1986 if (nidump == 0)
1987 nidump = 16;
1988 else if (nidump > MAX_DUMP)
1989 nidump = MAX_DUMP;
1990 adrs += ppc_inst_dump(adrs, nidump, 1);
1991 last_cmd = "di\n";
Olaf Hering7e5b5932006-03-08 20:40:28 +01001992 } else if (c == 'r') {
1993 scanhex(&ndump);
1994 if (ndump == 0)
1995 ndump = 64;
1996 xmon_rawdump(adrs, ndump);
1997 adrs += ndump;
1998 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 } else {
2000 scanhex(&ndump);
2001 if (ndump == 0)
2002 ndump = 64;
2003 else if (ndump > MAX_DUMP)
2004 ndump = MAX_DUMP;
2005 prdump(adrs, ndump);
2006 adrs += ndump;
2007 last_cmd = "d\n";
2008 }
2009}
2010
2011void
2012prdump(unsigned long adrs, long ndump)
2013{
2014 long n, m, c, r, nr;
2015 unsigned char temp[16];
2016
2017 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002018 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 putchar(' ');
2020 r = n < 16? n: 16;
2021 nr = mread(adrs, temp, r);
2022 adrs += nr;
2023 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002024 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2025 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 if (m < nr)
2027 printf("%.2x", temp[m]);
2028 else
2029 printf("%s", fault_chars[fault_type]);
2030 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002031 for (; m < 16; ++m) {
2032 if ((m & (sizeof(long) - 1)) == 0)
2033 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 printf(" |");
2037 for (m = 0; m < r; ++m) {
2038 if (m < nr) {
2039 c = temp[m];
2040 putchar(' ' <= c && c <= '~'? c: '.');
2041 } else
2042 putchar(' ');
2043 }
2044 n -= r;
2045 for (; m < 16; ++m)
2046 putchar(' ');
2047 printf("|\n");
2048 if (nr < r)
2049 break;
2050 }
2051}
2052
2053int
2054ppc_inst_dump(unsigned long adr, long count, int praddr)
2055{
2056 int nr, dotted;
2057 unsigned long first_adr;
2058 unsigned long inst, last_inst = 0;
2059 unsigned char val[4];
2060
2061 dotted = 0;
2062 for (first_adr = adr; count > 0; --count, adr += 4) {
2063 nr = mread(adr, val, 4);
2064 if (nr == 0) {
2065 if (praddr) {
2066 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002067 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 }
2069 break;
2070 }
2071 inst = GETWORD(val);
2072 if (adr > first_adr && inst == last_inst) {
2073 if (!dotted) {
2074 printf(" ...\n");
2075 dotted = 1;
2076 }
2077 continue;
2078 }
2079 dotted = 0;
2080 last_inst = inst;
2081 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002082 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 printf("\t");
2084 print_insn_powerpc(inst, adr, 0); /* always returns 4 */
2085 printf("\n");
2086 }
2087 return adr - first_adr;
2088}
2089
2090void
2091print_address(unsigned long addr)
2092{
2093 xmon_print_symbol(addr, "\t# ", "");
2094}
2095
2096
2097/*
2098 * Memory operations - move, set, print differences
2099 */
2100static unsigned long mdest; /* destination address */
2101static unsigned long msrc; /* source address */
2102static unsigned long mval; /* byte value to set memory to */
2103static unsigned long mcount; /* # bytes to affect */
2104static unsigned long mdiffs; /* max # differences to print */
2105
2106void
2107memops(int cmd)
2108{
2109 scanhex((void *)&mdest);
2110 if( termch != '\n' )
2111 termch = 0;
2112 scanhex((void *)(cmd == 's'? &mval: &msrc));
2113 if( termch != '\n' )
2114 termch = 0;
2115 scanhex((void *)&mcount);
2116 switch( cmd ){
2117 case 'm':
2118 memmove((void *)mdest, (void *)msrc, mcount);
2119 break;
2120 case 's':
2121 memset((void *)mdest, mval, mcount);
2122 break;
2123 case 'd':
2124 if( termch != '\n' )
2125 termch = 0;
2126 scanhex((void *)&mdiffs);
2127 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2128 break;
2129 }
2130}
2131
2132void
2133memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2134{
2135 unsigned n, prt;
2136
2137 prt = 0;
2138 for( n = nb; n > 0; --n )
2139 if( *p1++ != *p2++ )
2140 if( ++prt <= maxpr )
2141 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2142 p1[-1], p2 - 1, p2[-1]);
2143 if( prt > maxpr )
2144 printf("Total of %d differences\n", prt);
2145}
2146
2147static unsigned mend;
2148static unsigned mask;
2149
2150void
2151memlocate(void)
2152{
2153 unsigned a, n;
2154 unsigned char val[4];
2155
2156 last_cmd = "ml";
2157 scanhex((void *)&mdest);
2158 if (termch != '\n') {
2159 termch = 0;
2160 scanhex((void *)&mend);
2161 if (termch != '\n') {
2162 termch = 0;
2163 scanhex((void *)&mval);
2164 mask = ~0;
2165 if (termch != '\n') termch = 0;
2166 scanhex((void *)&mask);
2167 }
2168 }
2169 n = 0;
2170 for (a = mdest; a < mend; a += 4) {
2171 if (mread(a, val, 4) == 4
2172 && ((GETWORD(val) ^ mval) & mask) == 0) {
2173 printf("%.16x: %.16x\n", a, GETWORD(val));
2174 if (++n >= 10)
2175 break;
2176 }
2177 }
2178}
2179
2180static unsigned long mskip = 0x1000;
2181static unsigned long mlim = 0xffffffff;
2182
2183void
2184memzcan(void)
2185{
2186 unsigned char v;
2187 unsigned a;
2188 int ok, ook;
2189
2190 scanhex(&mdest);
2191 if (termch != '\n') termch = 0;
2192 scanhex(&mskip);
2193 if (termch != '\n') termch = 0;
2194 scanhex(&mlim);
2195 ook = 0;
2196 for (a = mdest; a < mlim; a += mskip) {
2197 ok = mread(a, &v, 1);
2198 if (ok && !ook) {
2199 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 } else if (!ok && ook)
2201 printf("%.8x\n", a - mskip);
2202 ook = ok;
2203 if (a + mskip < a)
2204 break;
2205 }
2206 if (ook)
2207 printf("%.8x\n", a - mskip);
2208}
2209
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002210void proccall(void)
2211{
2212 unsigned long args[8];
2213 unsigned long ret;
2214 int i;
2215 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2216 unsigned long, unsigned long, unsigned long,
2217 unsigned long, unsigned long, unsigned long);
2218 callfunc_t func;
2219
2220 if (!scanhex(&adrs))
2221 return;
2222 if (termch != '\n')
2223 termch = 0;
2224 for (i = 0; i < 8; ++i)
2225 args[i] = 0;
2226 for (i = 0; i < 8; ++i) {
2227 if (!scanhex(&args[i]) || termch == '\n')
2228 break;
2229 termch = 0;
2230 }
2231 func = (callfunc_t) adrs;
2232 ret = 0;
2233 if (setjmp(bus_error_jmp) == 0) {
2234 catch_memory_errors = 1;
2235 sync();
2236 ret = func(args[0], args[1], args[2], args[3],
2237 args[4], args[5], args[6], args[7]);
2238 sync();
2239 printf("return value is %x\n", ret);
2240 } else {
2241 printf("*** %x exception occurred\n", fault_except);
2242 }
2243 catch_memory_errors = 0;
2244}
2245
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246/* Input scanning routines */
2247int
2248skipbl(void)
2249{
2250 int c;
2251
2252 if( termch != 0 ){
2253 c = termch;
2254 termch = 0;
2255 } else
2256 c = inchar();
2257 while( c == ' ' || c == '\t' )
2258 c = inchar();
2259 return c;
2260}
2261
2262#define N_PTREGS 44
2263static char *regnames[N_PTREGS] = {
2264 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2265 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2266 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2267 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002268 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2269#ifdef CONFIG_PPC64
2270 "softe",
2271#else
2272 "mq",
2273#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 "trap", "dar", "dsisr", "res"
2275};
2276
2277int
2278scanhex(unsigned long *vp)
2279{
2280 int c, d;
2281 unsigned long v;
2282
2283 c = skipbl();
2284 if (c == '%') {
2285 /* parse register name */
2286 char regname[8];
2287 int i;
2288
2289 for (i = 0; i < sizeof(regname) - 1; ++i) {
2290 c = inchar();
2291 if (!isalnum(c)) {
2292 termch = c;
2293 break;
2294 }
2295 regname[i] = c;
2296 }
2297 regname[i] = 0;
2298 for (i = 0; i < N_PTREGS; ++i) {
2299 if (strcmp(regnames[i], regname) == 0) {
2300 if (xmon_regs == NULL) {
2301 printf("regs not available\n");
2302 return 0;
2303 }
2304 *vp = ((unsigned long *)xmon_regs)[i];
2305 return 1;
2306 }
2307 }
2308 printf("invalid register name '%%%s'\n", regname);
2309 return 0;
2310 }
2311
2312 /* skip leading "0x" if any */
2313
2314 if (c == '0') {
2315 c = inchar();
2316 if (c == 'x') {
2317 c = inchar();
2318 } else {
2319 d = hexdigit(c);
2320 if (d == EOF) {
2321 termch = c;
2322 *vp = 0;
2323 return 1;
2324 }
2325 }
2326 } else if (c == '$') {
2327 int i;
2328 for (i=0; i<63; i++) {
2329 c = inchar();
2330 if (isspace(c)) {
2331 termch = c;
2332 break;
2333 }
2334 tmpstr[i] = c;
2335 }
2336 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002337 *vp = 0;
2338 if (setjmp(bus_error_jmp) == 0) {
2339 catch_memory_errors = 1;
2340 sync();
2341 *vp = kallsyms_lookup_name(tmpstr);
2342 sync();
2343 }
2344 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 if (!(*vp)) {
2346 printf("unknown symbol '%s'\n", tmpstr);
2347 return 0;
2348 }
2349 return 1;
2350 }
2351
2352 d = hexdigit(c);
2353 if (d == EOF) {
2354 termch = c;
2355 return 0;
2356 }
2357 v = 0;
2358 do {
2359 v = (v << 4) + d;
2360 c = inchar();
2361 d = hexdigit(c);
2362 } while (d != EOF);
2363 termch = c;
2364 *vp = v;
2365 return 1;
2366}
2367
2368void
2369scannl(void)
2370{
2371 int c;
2372
2373 c = termch;
2374 termch = 0;
2375 while( c != '\n' )
2376 c = inchar();
2377}
2378
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002379int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380{
2381 if( '0' <= c && c <= '9' )
2382 return c - '0';
2383 if( 'A' <= c && c <= 'F' )
2384 return c - ('A' - 10);
2385 if( 'a' <= c && c <= 'f' )
2386 return c - ('a' - 10);
2387 return EOF;
2388}
2389
2390void
2391getstring(char *s, int size)
2392{
2393 int c;
2394
2395 c = skipbl();
2396 do {
2397 if( size > 1 ){
2398 *s++ = c;
2399 --size;
2400 }
2401 c = inchar();
2402 } while( c != ' ' && c != '\t' && c != '\n' );
2403 termch = c;
2404 *s = 0;
2405}
2406
2407static char line[256];
2408static char *lineptr;
2409
2410void
2411flush_input(void)
2412{
2413 lineptr = NULL;
2414}
2415
2416int
2417inchar(void)
2418{
2419 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002420 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 lineptr = NULL;
2422 return EOF;
2423 }
2424 lineptr = line;
2425 }
2426 return *lineptr++;
2427}
2428
2429void
2430take_input(char *str)
2431{
2432 lineptr = str;
2433}
2434
2435
2436static void
2437symbol_lookup(void)
2438{
2439 int type = inchar();
2440 unsigned long addr;
2441 static char tmp[64];
2442
2443 switch (type) {
2444 case 'a':
2445 if (scanhex(&addr))
2446 xmon_print_symbol(addr, ": ", "\n");
2447 termch = 0;
2448 break;
2449 case 's':
2450 getstring(tmp, 64);
2451 if (setjmp(bus_error_jmp) == 0) {
2452 catch_memory_errors = 1;
2453 sync();
2454 addr = kallsyms_lookup_name(tmp);
2455 if (addr)
2456 printf("%s: %lx\n", tmp, addr);
2457 else
2458 printf("Symbol '%s' not found.\n", tmp);
2459 sync();
2460 }
2461 catch_memory_errors = 0;
2462 termch = 0;
2463 break;
2464 }
2465}
2466
2467
2468/* Print an address in numeric and symbolic form (if possible) */
2469static void xmon_print_symbol(unsigned long address, const char *mid,
2470 const char *after)
2471{
2472 char *modname;
2473 const char *name = NULL;
2474 unsigned long offset, size;
2475
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002476 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 if (setjmp(bus_error_jmp) == 0) {
2478 catch_memory_errors = 1;
2479 sync();
2480 name = kallsyms_lookup(address, &size, &offset, &modname,
2481 tmpstr);
2482 sync();
2483 /* wait a little while to see if we get a machine check */
2484 __delay(200);
2485 }
2486
2487 catch_memory_errors = 0;
2488
2489 if (name) {
2490 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2491 if (modname)
2492 printf(" [%s]", modname);
2493 }
2494 printf("%s", after);
2495}
2496
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002497#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498static void dump_slb(void)
2499{
2500 int i;
2501 unsigned long tmp;
2502
2503 printf("SLB contents of cpu %x\n", smp_processor_id());
2504
2505 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2506 asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
2507 printf("%02d %016lx ", i, tmp);
2508
2509 asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
2510 printf("%016lx\n", tmp);
2511 }
2512}
2513
2514static void dump_stab(void)
2515{
2516 int i;
2517 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2518
2519 printf("Segment table contents of cpu %x\n", smp_processor_id());
2520
2521 for (i = 0; i < PAGE_SIZE/16; i++) {
2522 unsigned long a, b;
2523
2524 a = *tmp++;
2525 b = *tmp++;
2526
2527 if (a || b) {
2528 printf("%03d %016lx ", i, a);
2529 printf("%016lx\n", b);
2530 }
2531 }
2532}
2533
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002534void dump_segments(void)
2535{
2536 if (cpu_has_feature(CPU_FTR_SLB))
2537 dump_slb();
2538 else
2539 dump_stab();
2540}
2541#endif
2542
2543#ifdef CONFIG_PPC_STD_MMU_32
2544void dump_segments(void)
2545{
2546 int i;
2547
2548 printf("sr0-15 =");
2549 for (i = 0; i < 16; ++i)
2550 printf(" %x", mfsrin(i));
2551 printf("\n");
2552}
2553#endif
2554
Olaf Heringb13cfd172005-08-04 19:26:42 +02002555void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002557 if (enable) {
2558 __debugger = xmon;
2559 __debugger_ipi = xmon_ipi;
2560 __debugger_bpt = xmon_bpt;
2561 __debugger_sstep = xmon_sstep;
2562 __debugger_iabr_match = xmon_iabr_match;
2563 __debugger_dabr_match = xmon_dabr_match;
2564 __debugger_fault_handler = xmon_fault_handler;
2565 } else {
2566 __debugger = NULL;
2567 __debugger_ipi = NULL;
2568 __debugger_bpt = NULL;
2569 __debugger_sstep = NULL;
2570 __debugger_iabr_match = NULL;
2571 __debugger_dabr_match = NULL;
2572 __debugger_fault_handler = NULL;
2573 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002574 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002576
2577#ifdef CONFIG_MAGIC_SYSRQ
2578static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
2579 struct tty_struct *tty)
2580{
2581 /* ensure xmon is enabled */
2582 xmon_init(1);
2583 debugger(pt_regs);
2584}
2585
2586static struct sysrq_key_op sysrq_xmon_op =
2587{
2588 .handler = sysrq_handle_xmon,
2589 .help_msg = "Xmon",
2590 .action_msg = "Entering xmon",
2591};
2592
2593static int __init setup_xmon_sysrq(void)
2594{
2595 register_sysrq_key('x', &sysrq_xmon_op);
2596 return 0;
2597}
2598__initcall(setup_xmon_sysrq);
2599#endif /* CONFIG_MAGIC_SYSRQ */