blob: 4735b41c113c7d7814a1ecff82451cb69d2f05b2 [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 */
11#include <linux/config.h>
12#include <linux/errno.h>
13#include <linux/sched.h>
14#include <linux/smp.h>
15#include <linux/mm.h>
16#include <linux/reboot.h>
17#include <linux/delay.h>
18#include <linux/kallsyms.h>
19#include <linux/cpumask.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100020#include <linux/module.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110021#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080022#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24#include <asm/ptrace.h>
25#include <asm/string.h>
26#include <asm/prom.h>
27#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100028#include <asm/xmon.h>
29#ifdef CONFIG_PMAC_BACKLIGHT
30#include <asm/backlight.h>
31#endif
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>
39#include <asm/bug.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100040
41#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100043#include <asm/paca.h>
44#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46#include "nonstdio.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#define scanhex xmon_scanhex
49#define skipbl xmon_skipbl
50
51#ifdef CONFIG_SMP
52cpumask_t cpus_in_xmon = CPU_MASK_NONE;
53static unsigned long xmon_taken = 1;
54static int xmon_owner;
55static int xmon_gate;
56#endif /* CONFIG_SMP */
57
58static unsigned long in_xmon = 0;
59
60static unsigned long adrs;
61static int size = 1;
62#define MAX_DUMP (128 * 1024)
63static unsigned long ndump = 64;
64static unsigned long nidump = 16;
65static unsigned long ncsum = 4096;
66static int termch;
67static char tmpstr[128];
68
Paul Mackerrasf78541d2005-10-28 22:53:37 +100069#define JMP_BUF_LEN 23
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static long bus_error_jmp[JMP_BUF_LEN];
71static int catch_memory_errors;
72static long *xmon_fault_jmp[NR_CPUS];
73#define setjmp xmon_setjmp
74#define longjmp xmon_longjmp
75
76/* Breakpoint stuff */
77struct bpt {
78 unsigned long address;
79 unsigned int instr[2];
80 atomic_t ref_count;
81 int enabled;
82 unsigned long pad;
83};
84
85/* Bits in bpt.enabled */
86#define BP_IABR_TE 1 /* IABR translation enabled */
87#define BP_IABR 2
88#define BP_TRAP 8
89#define BP_DABR 0x10
90
91#define NBPTS 256
92static struct bpt bpts[NBPTS];
93static struct bpt dabr;
94static struct bpt *iabr;
95static unsigned bpinstr = 0x7fe00008; /* trap */
96
97#define BP_NUM(bp) ((bp) - bpts + 1)
98
99/* Prototypes */
100static int cmds(struct pt_regs *);
101static int mread(unsigned long, void *, int);
102static int mwrite(unsigned long, void *, int);
103static int handle_fault(struct pt_regs *);
104static void byterev(unsigned char *, int);
105static void memex(void);
106static int bsesc(void);
107static void dump(void);
108static void prdump(unsigned long, long);
109static int ppc_inst_dump(unsigned long, long, int);
110void print_address(unsigned long);
111static void backtrace(struct pt_regs *);
112static void excprint(struct pt_regs *);
113static void prregs(struct pt_regs *);
114static void memops(int);
115static void memlocate(void);
116static void memzcan(void);
117static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
118int skipbl(void);
119int scanhex(unsigned long *valp);
120static void scannl(void);
121static int hexdigit(int);
122void getstring(char *, int);
123static void flush_input(void);
124static int inchar(void);
125static void take_input(char *);
126static unsigned long read_spr(int);
127static void write_spr(int, unsigned long);
128static void super_regs(void);
129static void remove_bpts(void);
130static void insert_bpts(void);
131static void remove_cpu_bpts(void);
132static void insert_cpu_bpts(void);
133static struct bpt *at_breakpoint(unsigned long pc);
134static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
135static int do_step(struct pt_regs *);
136static void bpt_cmds(void);
137static void cacheflush(void);
138static int cpu_cmd(void);
139static void csum(void);
140static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000141static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142void dump_segments(void);
143static void symbol_lookup(void);
144static void xmon_print_symbol(unsigned long address, const char *mid,
145 const char *after);
146static const char *getvecname(unsigned long vec);
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;
743 for(;;) {
744#ifdef CONFIG_SMP
745 printf("%x:", smp_processor_id());
746#endif /* CONFIG_SMP */
747 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 flush_input();
749 termch = 0;
750 cmd = skipbl();
751 if( cmd == '\n' ) {
752 if (last_cmd == NULL)
753 continue;
754 take_input(last_cmd);
755 last_cmd = NULL;
756 cmd = inchar();
757 }
758 switch (cmd) {
759 case 'm':
760 cmd = inchar();
761 switch (cmd) {
762 case 'm':
763 case 's':
764 case 'd':
765 memops(cmd);
766 break;
767 case 'l':
768 memlocate();
769 break;
770 case 'z':
771 memzcan();
772 break;
773 case 'i':
774 show_mem();
775 break;
776 default:
777 termch = cmd;
778 memex();
779 }
780 break;
781 case 'd':
782 dump();
783 break;
784 case 'l':
785 symbol_lookup();
786 break;
787 case 'r':
788 prregs(excp); /* print regs */
789 break;
790 case 'e':
791 excprint(excp);
792 break;
793 case 'S':
794 super_regs();
795 break;
796 case 't':
797 backtrace(excp);
798 break;
799 case 'f':
800 cacheflush();
801 break;
802 case 's':
803 if (do_step(excp))
804 return cmd;
805 break;
806 case 'x':
807 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100808 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100810 printf(" <no input ...>\n");
811 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 return cmd;
813 case '?':
814 printf(help_string);
815 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 case 'b':
817 bpt_cmds();
818 break;
819 case 'C':
820 csum();
821 break;
822 case 'c':
823 if (cpu_cmd())
824 return 0;
825 break;
826 case 'z':
827 bootcmds();
828 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000829 case 'p':
830 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000832#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 case 'u':
834 dump_segments();
835 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000836#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 default:
838 printf("Unrecognized command: ");
839 do {
840 if (' ' < cmd && cmd <= '~')
841 putchar(cmd);
842 else
843 printf("\\x%x", cmd);
844 cmd = inchar();
845 } while (cmd != '\n');
846 printf(" (type ? for help)\n");
847 break;
848 }
849 }
850}
851
852/*
853 * Step a single instruction.
854 * Some instructions we emulate, others we execute with MSR_SE set.
855 */
856static int do_step(struct pt_regs *regs)
857{
858 unsigned int instr;
859 int stepped;
860
861 /* check we are in 64-bit kernel mode, translation enabled */
862 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
863 if (mread(regs->nip, &instr, 4) == 4) {
864 stepped = emulate_step(regs, instr);
865 if (stepped < 0) {
866 printf("Couldn't single-step %s instruction\n",
867 (IS_RFID(instr)? "rfid": "mtmsrd"));
868 return 0;
869 }
870 if (stepped > 0) {
871 regs->trap = 0xd00 | (regs->trap & 1);
872 printf("stepped to ");
873 xmon_print_symbol(regs->nip, " ", "\n");
874 ppc_inst_dump(regs->nip, 1, 0);
875 return 0;
876 }
877 }
878 }
879 regs->msr |= MSR_SE;
880 return 1;
881}
882
883static void bootcmds(void)
884{
885 int cmd;
886
887 cmd = inchar();
888 if (cmd == 'r')
889 ppc_md.restart(NULL);
890 else if (cmd == 'h')
891 ppc_md.halt();
892 else if (cmd == 'p')
893 ppc_md.power_off();
894}
895
896static int cpu_cmd(void)
897{
898#ifdef CONFIG_SMP
899 unsigned long cpu;
900 int timeout;
901 int count;
902
903 if (!scanhex(&cpu)) {
904 /* print cpus waiting or in xmon */
905 printf("cpus stopped:");
906 count = 0;
907 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
908 if (cpu_isset(cpu, cpus_in_xmon)) {
909 if (count == 0)
910 printf(" %x", cpu);
911 ++count;
912 } else {
913 if (count > 1)
914 printf("-%x", cpu - 1);
915 count = 0;
916 }
917 }
918 if (count > 1)
919 printf("-%x", NR_CPUS - 1);
920 printf("\n");
921 return 0;
922 }
923 /* try to switch to cpu specified */
924 if (!cpu_isset(cpu, cpus_in_xmon)) {
925 printf("cpu 0x%x isn't in xmon\n", cpu);
926 return 0;
927 }
928 xmon_taken = 0;
929 mb();
930 xmon_owner = cpu;
931 timeout = 10000000;
932 while (!xmon_taken) {
933 if (--timeout == 0) {
934 if (test_and_set_bit(0, &xmon_taken))
935 break;
936 /* take control back */
937 mb();
938 xmon_owner = smp_processor_id();
939 printf("cpu %u didn't take control\n", cpu);
940 return 0;
941 }
942 barrier();
943 }
944 return 1;
945#else
946 return 0;
947#endif /* CONFIG_SMP */
948}
949
950static unsigned short fcstab[256] = {
951 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
952 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
953 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
954 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
955 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
956 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
957 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
958 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
959 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
960 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
961 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
962 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
963 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
964 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
965 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
966 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
967 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
968 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
969 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
970 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
971 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
972 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
973 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
974 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
975 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
976 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
977 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
978 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
979 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
980 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
981 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
982 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
983};
984
985#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
986
987static void
988csum(void)
989{
990 unsigned int i;
991 unsigned short fcs;
992 unsigned char v;
993
994 if (!scanhex(&adrs))
995 return;
996 if (!scanhex(&ncsum))
997 return;
998 fcs = 0xffff;
999 for (i = 0; i < ncsum; ++i) {
1000 if (mread(adrs+i, &v, 1) == 0) {
1001 printf("csum stopped at %x\n", adrs+i);
1002 break;
1003 }
1004 fcs = FCS(fcs, v);
1005 }
1006 printf("%x\n", fcs);
1007}
1008
1009/*
1010 * Check if this is a suitable place to put a breakpoint.
1011 */
1012static long check_bp_loc(unsigned long addr)
1013{
1014 unsigned int instr;
1015
1016 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001017 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 printf("Breakpoints may only be placed at kernel addresses\n");
1019 return 0;
1020 }
1021 if (!mread(addr, &instr, sizeof(instr))) {
1022 printf("Can't read instruction at address %lx\n", addr);
1023 return 0;
1024 }
1025 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1026 printf("Breakpoints may not be placed on mtmsrd or rfid "
1027 "instructions\n");
1028 return 0;
1029 }
1030 return 1;
1031}
1032
1033static char *breakpoint_help_string =
1034 "Breakpoint command usage:\n"
1035 "b show breakpoints\n"
1036 "b <addr> [cnt] set breakpoint at given instr addr\n"
1037 "bc clear all breakpoints\n"
1038 "bc <n/addr> clear breakpoint number n or at addr\n"
1039 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1040 "bd <addr> [cnt] set hardware data breakpoint\n"
1041 "";
1042
1043static void
1044bpt_cmds(void)
1045{
1046 int cmd;
1047 unsigned long a;
1048 int mode, i;
1049 struct bpt *bp;
1050 const char badaddr[] = "Only kernel addresses are permitted "
1051 "for breakpoints\n";
1052
1053 cmd = inchar();
1054 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001055#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 case 'd': /* bd - hardware data breakpoint */
1057 mode = 7;
1058 cmd = inchar();
1059 if (cmd == 'r')
1060 mode = 5;
1061 else if (cmd == 'w')
1062 mode = 6;
1063 else
1064 termch = cmd;
1065 dabr.address = 0;
1066 dabr.enabled = 0;
1067 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001068 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 printf(badaddr);
1070 break;
1071 }
1072 dabr.address &= ~7;
1073 dabr.enabled = mode | BP_DABR;
1074 }
1075 break;
1076
1077 case 'i': /* bi - hardware instr breakpoint */
1078 if (!cpu_has_feature(CPU_FTR_IABR)) {
1079 printf("Hardware instruction breakpoint "
1080 "not supported on this cpu\n");
1081 break;
1082 }
1083 if (iabr) {
1084 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1085 iabr = NULL;
1086 }
1087 if (!scanhex(&a))
1088 break;
1089 if (!check_bp_loc(a))
1090 break;
1091 bp = new_breakpoint(a);
1092 if (bp != NULL) {
1093 bp->enabled |= BP_IABR | BP_IABR_TE;
1094 iabr = bp;
1095 }
1096 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001097#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 case 'c':
1100 if (!scanhex(&a)) {
1101 /* clear all breakpoints */
1102 for (i = 0; i < NBPTS; ++i)
1103 bpts[i].enabled = 0;
1104 iabr = NULL;
1105 dabr.enabled = 0;
1106 printf("All breakpoints cleared\n");
1107 break;
1108 }
1109
1110 if (a <= NBPTS && a >= 1) {
1111 /* assume a breakpoint number */
1112 bp = &bpts[a-1]; /* bp nums are 1 based */
1113 } else {
1114 /* assume a breakpoint address */
1115 bp = at_breakpoint(a);
1116 if (bp == 0) {
1117 printf("No breakpoint at %x\n", a);
1118 break;
1119 }
1120 }
1121
1122 printf("Cleared breakpoint %x (", BP_NUM(bp));
1123 xmon_print_symbol(bp->address, " ", ")\n");
1124 bp->enabled = 0;
1125 break;
1126
1127 default:
1128 termch = cmd;
1129 cmd = skipbl();
1130 if (cmd == '?') {
1131 printf(breakpoint_help_string);
1132 break;
1133 }
1134 termch = cmd;
1135 if (!scanhex(&a)) {
1136 /* print all breakpoints */
1137 printf(" type address\n");
1138 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001139 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 if (dabr.enabled & 1)
1141 printf("r");
1142 if (dabr.enabled & 2)
1143 printf("w");
1144 printf("]\n");
1145 }
1146 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1147 if (!bp->enabled)
1148 continue;
1149 printf("%2x %s ", BP_NUM(bp),
1150 (bp->enabled & BP_IABR)? "inst": "trap");
1151 xmon_print_symbol(bp->address, " ", "\n");
1152 }
1153 break;
1154 }
1155
1156 if (!check_bp_loc(a))
1157 break;
1158 bp = new_breakpoint(a);
1159 if (bp != NULL)
1160 bp->enabled |= BP_TRAP;
1161 break;
1162 }
1163}
1164
1165/* Very cheap human name for vector lookup. */
1166static
1167const char *getvecname(unsigned long vec)
1168{
1169 char *ret;
1170
1171 switch (vec) {
1172 case 0x100: ret = "(System Reset)"; break;
1173 case 0x200: ret = "(Machine Check)"; break;
1174 case 0x300: ret = "(Data Access)"; break;
1175 case 0x380: ret = "(Data SLB Access)"; break;
1176 case 0x400: ret = "(Instruction Access)"; break;
1177 case 0x480: ret = "(Instruction SLB Access)"; break;
1178 case 0x500: ret = "(Hardware Interrupt)"; break;
1179 case 0x600: ret = "(Alignment)"; break;
1180 case 0x700: ret = "(Program Check)"; break;
1181 case 0x800: ret = "(FPU Unavailable)"; break;
1182 case 0x900: ret = "(Decrementer)"; break;
1183 case 0xc00: ret = "(System Call)"; break;
1184 case 0xd00: ret = "(Single Step)"; break;
1185 case 0xf00: ret = "(Performance Monitor)"; break;
1186 case 0xf20: ret = "(Altivec Unavailable)"; break;
1187 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1188 default: ret = "";
1189 }
1190 return ret;
1191}
1192
1193static void get_function_bounds(unsigned long pc, unsigned long *startp,
1194 unsigned long *endp)
1195{
1196 unsigned long size, offset;
1197 const char *name;
1198 char *modname;
1199
1200 *startp = *endp = 0;
1201 if (pc == 0)
1202 return;
1203 if (setjmp(bus_error_jmp) == 0) {
1204 catch_memory_errors = 1;
1205 sync();
1206 name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
1207 if (name != NULL) {
1208 *startp = pc - offset;
1209 *endp = pc - offset + size;
1210 }
1211 sync();
1212 }
1213 catch_memory_errors = 0;
1214}
1215
1216static int xmon_depth_to_print = 64;
1217
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001218#ifdef CONFIG_PPC64
1219#define LRSAVE_OFFSET 0x10
1220#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1221#define MARKER_OFFSET 0x60
1222#define REGS_OFFSET 0x70
1223#else
1224#define LRSAVE_OFFSET 4
1225#define REG_FRAME_MARKER 0x72656773
1226#define MARKER_OFFSET 8
1227#define REGS_OFFSET 16
1228#endif
1229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230static void xmon_show_stack(unsigned long sp, unsigned long lr,
1231 unsigned long pc)
1232{
1233 unsigned long ip;
1234 unsigned long newsp;
1235 unsigned long marker;
1236 int count = 0;
1237 struct pt_regs regs;
1238
1239 do {
1240 if (sp < PAGE_OFFSET) {
1241 if (sp != 0)
1242 printf("SP (%lx) is in userspace\n", sp);
1243 break;
1244 }
1245
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001246 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 || !mread(sp, &newsp, sizeof(unsigned long))) {
1248 printf("Couldn't read stack frame at %lx\n", sp);
1249 break;
1250 }
1251
1252 /*
1253 * For the first stack frame, try to work out if
1254 * LR and/or the saved LR value in the bottommost
1255 * stack frame are valid.
1256 */
1257 if ((pc | lr) != 0) {
1258 unsigned long fnstart, fnend;
1259 unsigned long nextip;
1260 int printip = 1;
1261
1262 get_function_bounds(pc, &fnstart, &fnend);
1263 nextip = 0;
1264 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001265 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 sizeof(unsigned long));
1267 if (lr == ip) {
1268 if (lr < PAGE_OFFSET
1269 || (fnstart <= lr && lr < fnend))
1270 printip = 0;
1271 } else if (lr == nextip) {
1272 printip = 0;
1273 } else if (lr >= PAGE_OFFSET
1274 && !(fnstart <= lr && lr < fnend)) {
1275 printf("[link register ] ");
1276 xmon_print_symbol(lr, " ", "\n");
1277 }
1278 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001279 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 xmon_print_symbol(ip, " ", " (unreliable)\n");
1281 }
1282 pc = lr = 0;
1283
1284 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001285 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 xmon_print_symbol(ip, " ", "\n");
1287 }
1288
1289 /* Look for "regshere" marker to see if this is
1290 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001291 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1292 && marker == REG_FRAME_MARKER) {
1293 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 != sizeof(regs)) {
1295 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001296 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 break;
1298 }
1299 printf("--- Exception: %lx %s at ", regs.trap,
1300 getvecname(TRAP(&regs)));
1301 pc = regs.nip;
1302 lr = regs.link;
1303 xmon_print_symbol(pc, " ", "\n");
1304 }
1305
1306 if (newsp == 0)
1307 break;
1308
1309 sp = newsp;
1310 } while (count++ < xmon_depth_to_print);
1311}
1312
1313static void backtrace(struct pt_regs *excp)
1314{
1315 unsigned long sp;
1316
1317 if (scanhex(&sp))
1318 xmon_show_stack(sp, 0, 0);
1319 else
1320 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1321 scannl();
1322}
1323
1324static void print_bug_trap(struct pt_regs *regs)
1325{
1326 struct bug_entry *bug;
1327 unsigned long addr;
1328
1329 if (regs->msr & MSR_PR)
1330 return; /* not in kernel */
1331 addr = regs->nip; /* address of trap instruction */
1332 if (addr < PAGE_OFFSET)
1333 return;
1334 bug = find_bug(regs->nip);
1335 if (bug == NULL)
1336 return;
1337 if (bug->line & BUG_WARNING_TRAP)
1338 return;
1339
1340 printf("kernel BUG in %s at %s:%d!\n",
1341 bug->function, bug->file, (unsigned int)bug->line);
1342}
1343
1344void excprint(struct pt_regs *fp)
1345{
1346 unsigned long trap;
1347
1348#ifdef CONFIG_SMP
1349 printf("cpu 0x%x: ", smp_processor_id());
1350#endif /* CONFIG_SMP */
1351
1352 trap = TRAP(fp);
1353 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1354 printf(" pc: ");
1355 xmon_print_symbol(fp->nip, ": ", "\n");
1356
1357 printf(" lr: ", fp->link);
1358 xmon_print_symbol(fp->link, ": ", "\n");
1359
1360 printf(" sp: %lx\n", fp->gpr[1]);
1361 printf(" msr: %lx\n", fp->msr);
1362
1363 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1364 printf(" dar: %lx\n", fp->dar);
1365 if (trap != 0x380)
1366 printf(" dsisr: %lx\n", fp->dsisr);
1367 }
1368
1369 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001370#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001372#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (current) {
1374 printf(" pid = %ld, comm = %s\n",
1375 current->pid, current->comm);
1376 }
1377
1378 if (trap == 0x700)
1379 print_bug_trap(fp);
1380}
1381
1382void prregs(struct pt_regs *fp)
1383{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001384 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 unsigned long base;
1386 struct pt_regs regs;
1387
1388 if (scanhex(&base)) {
1389 if (setjmp(bus_error_jmp) == 0) {
1390 catch_memory_errors = 1;
1391 sync();
1392 regs = *(struct pt_regs *)base;
1393 sync();
1394 __delay(200);
1395 } else {
1396 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001397 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 base);
1399 return;
1400 }
1401 catch_memory_errors = 0;
1402 fp = &regs;
1403 }
1404
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001405#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (FULL_REGS(fp)) {
1407 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001408 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1410 } else {
1411 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001412 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1414 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001415#else
1416 for (n = 0; n < 32; ++n) {
1417 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1418 (n & 3) == 3? "\n": " ");
1419 if (n == 12 && !FULL_REGS(fp)) {
1420 printf("\n");
1421 break;
1422 }
1423 }
1424#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 printf("pc = ");
1426 xmon_print_symbol(fp->nip, " ", "\n");
1427 printf("lr = ");
1428 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001429 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1430 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001432 trap = TRAP(fp);
1433 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1434 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435}
1436
1437void cacheflush(void)
1438{
1439 int cmd;
1440 unsigned long nflush;
1441
1442 cmd = inchar();
1443 if (cmd != 'i')
1444 termch = cmd;
1445 scanhex((void *)&adrs);
1446 if (termch != '\n')
1447 termch = 0;
1448 nflush = 1;
1449 scanhex(&nflush);
1450 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1451 if (setjmp(bus_error_jmp) == 0) {
1452 catch_memory_errors = 1;
1453 sync();
1454
1455 if (cmd != 'i') {
1456 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1457 cflush((void *) adrs);
1458 } else {
1459 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1460 cinval((void *) adrs);
1461 }
1462 sync();
1463 /* wait a little while to see if we get a machine check */
1464 __delay(200);
1465 }
1466 catch_memory_errors = 0;
1467}
1468
1469unsigned long
1470read_spr(int n)
1471{
1472 unsigned int instrs[2];
1473 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001475#ifdef CONFIG_PPC64
1476 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 opd[0] = (unsigned long)instrs;
1479 opd[1] = 0;
1480 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001481 code = (unsigned long (*)(void)) opd;
1482#else
1483 code = (unsigned long (*)(void)) instrs;
1484#endif
1485
1486 /* mfspr r3,n; blr */
1487 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1488 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 store_inst(instrs);
1490 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
1492 if (setjmp(bus_error_jmp) == 0) {
1493 catch_memory_errors = 1;
1494 sync();
1495
1496 ret = code();
1497
1498 sync();
1499 /* wait a little while to see if we get a machine check */
1500 __delay(200);
1501 n = size;
1502 }
1503
1504 return ret;
1505}
1506
1507void
1508write_spr(int n, unsigned long val)
1509{
1510 unsigned int instrs[2];
1511 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001512#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 unsigned long opd[3];
1514
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 opd[0] = (unsigned long)instrs;
1516 opd[1] = 0;
1517 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001518 code = (unsigned long (*)(unsigned long)) opd;
1519#else
1520 code = (unsigned long (*)(unsigned long)) instrs;
1521#endif
1522
1523 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1524 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 store_inst(instrs);
1526 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 if (setjmp(bus_error_jmp) == 0) {
1529 catch_memory_errors = 1;
1530 sync();
1531
1532 code(val);
1533
1534 sync();
1535 /* wait a little while to see if we get a machine check */
1536 __delay(200);
1537 n = size;
1538 }
1539}
1540
1541static unsigned long regno;
1542extern char exc_prolog;
1543extern char dec_exc;
1544
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001545void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546{
1547 int cmd;
1548 unsigned long val;
1549#ifdef CONFIG_PPC_ISERIES
1550 struct paca_struct *ptrPaca = NULL;
1551 struct lppaca *ptrLpPaca = NULL;
1552 struct ItLpRegSave *ptrLpRegSave = NULL;
1553#endif
1554
1555 cmd = skipbl();
1556 if (cmd == '\n') {
1557 unsigned long sp, toc;
1558 asm("mr %0,1" : "=r" (sp) :);
1559 asm("mr %0,2" : "=r" (toc) :);
1560
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001561 printf("msr = "REG" sprg0= "REG"\n",
1562 mfmsr(), mfspr(SPRN_SPRG0));
1563 printf("pvr = "REG" sprg1= "REG"\n",
1564 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1565 printf("dec = "REG" sprg2= "REG"\n",
1566 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1567 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1568 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569#ifdef CONFIG_PPC_ISERIES
1570 // Dump out relevant Paca data areas.
1571 printf("Paca: \n");
1572 ptrPaca = get_paca();
1573
1574 printf(" Local Processor Control Area (LpPaca): \n");
1575 ptrLpPaca = ptrPaca->lppaca_ptr;
1576 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1577 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1578 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1579 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1580 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1581
1582 printf(" Local Processor Register Save Area (LpRegSave): \n");
1583 ptrLpRegSave = ptrPaca->reg_save_ptr;
1584 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1585 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1586 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1587 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1588 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1589 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1590#endif
1591
1592 return;
1593 }
1594
1595 scanhex(&regno);
1596 switch (cmd) {
1597 case 'w':
1598 val = read_spr(regno);
1599 scanhex(&val);
1600 write_spr(regno, val);
1601 /* fall through */
1602 case 'r':
1603 printf("spr %lx = %lx\n", regno, read_spr(regno));
1604 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 }
1606 scannl();
1607}
1608
1609/*
1610 * Stuff for reading and writing memory safely
1611 */
1612int
1613mread(unsigned long adrs, void *buf, int size)
1614{
1615 volatile int n;
1616 char *p, *q;
1617
1618 n = 0;
1619 if (setjmp(bus_error_jmp) == 0) {
1620 catch_memory_errors = 1;
1621 sync();
1622 p = (char *)adrs;
1623 q = (char *)buf;
1624 switch (size) {
1625 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001626 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 break;
1628 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001629 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 break;
1631 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001632 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 break;
1634 default:
1635 for( ; n < size; ++n) {
1636 *q++ = *p++;
1637 sync();
1638 }
1639 }
1640 sync();
1641 /* wait a little while to see if we get a machine check */
1642 __delay(200);
1643 n = size;
1644 }
1645 catch_memory_errors = 0;
1646 return n;
1647}
1648
1649int
1650mwrite(unsigned long adrs, void *buf, int size)
1651{
1652 volatile int n;
1653 char *p, *q;
1654
1655 n = 0;
1656 if (setjmp(bus_error_jmp) == 0) {
1657 catch_memory_errors = 1;
1658 sync();
1659 p = (char *) adrs;
1660 q = (char *) buf;
1661 switch (size) {
1662 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001663 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 break;
1665 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001666 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 break;
1668 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001669 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 break;
1671 default:
1672 for ( ; n < size; ++n) {
1673 *p++ = *q++;
1674 sync();
1675 }
1676 }
1677 sync();
1678 /* wait a little while to see if we get a machine check */
1679 __delay(200);
1680 n = size;
1681 } else {
1682 printf("*** Error writing address %x\n", adrs + n);
1683 }
1684 catch_memory_errors = 0;
1685 return n;
1686}
1687
1688static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001689static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690static char *fault_chars[] = { "--", "**", "##" };
1691
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001692static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001694 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 switch (TRAP(regs)) {
1696 case 0x200:
1697 fault_type = 0;
1698 break;
1699 case 0x300:
1700 case 0x380:
1701 fault_type = 1;
1702 break;
1703 default:
1704 fault_type = 2;
1705 }
1706
1707 longjmp(bus_error_jmp, 1);
1708
1709 return 0;
1710}
1711
1712#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1713
1714void
1715byterev(unsigned char *val, int size)
1716{
1717 int t;
1718
1719 switch (size) {
1720 case 2:
1721 SWAP(val[0], val[1], t);
1722 break;
1723 case 4:
1724 SWAP(val[0], val[3], t);
1725 SWAP(val[1], val[2], t);
1726 break;
1727 case 8: /* is there really any use for this? */
1728 SWAP(val[0], val[7], t);
1729 SWAP(val[1], val[6], t);
1730 SWAP(val[2], val[5], t);
1731 SWAP(val[3], val[4], t);
1732 break;
1733 }
1734}
1735
1736static int brev;
1737static int mnoread;
1738
1739static char *memex_help_string =
1740 "Memory examine command usage:\n"
1741 "m [addr] [flags] examine/change memory\n"
1742 " addr is optional. will start where left off.\n"
1743 " flags may include chars from this set:\n"
1744 " b modify by bytes (default)\n"
1745 " w modify by words (2 byte)\n"
1746 " l modify by longs (4 byte)\n"
1747 " d modify by doubleword (8 byte)\n"
1748 " r toggle reverse byte order mode\n"
1749 " n do not read memory (for i/o spaces)\n"
1750 " . ok to read (default)\n"
1751 "NOTE: flags are saved as defaults\n"
1752 "";
1753
1754static char *memex_subcmd_help_string =
1755 "Memory examine subcommands:\n"
1756 " hexval write this val to current location\n"
1757 " 'string' write chars from string to this location\n"
1758 " ' increment address\n"
1759 " ^ decrement address\n"
1760 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1761 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1762 " ` clear no-read flag\n"
1763 " ; stay at this addr\n"
1764 " v change to byte mode\n"
1765 " w change to word (2 byte) mode\n"
1766 " l change to long (4 byte) mode\n"
1767 " u change to doubleword (8 byte) mode\n"
1768 " m addr change current addr\n"
1769 " n toggle no-read flag\n"
1770 " r toggle byte reverse flag\n"
1771 " < count back up count bytes\n"
1772 " > count skip forward count bytes\n"
1773 " x exit this mode\n"
1774 "";
1775
1776void
1777memex(void)
1778{
1779 int cmd, inc, i, nslash;
1780 unsigned long n;
1781 unsigned char val[16];
1782
1783 scanhex((void *)&adrs);
1784 cmd = skipbl();
1785 if (cmd == '?') {
1786 printf(memex_help_string);
1787 return;
1788 } else {
1789 termch = cmd;
1790 }
1791 last_cmd = "m\n";
1792 while ((cmd = skipbl()) != '\n') {
1793 switch( cmd ){
1794 case 'b': size = 1; break;
1795 case 'w': size = 2; break;
1796 case 'l': size = 4; break;
1797 case 'd': size = 8; break;
1798 case 'r': brev = !brev; break;
1799 case 'n': mnoread = 1; break;
1800 case '.': mnoread = 0; break;
1801 }
1802 }
1803 if( size <= 0 )
1804 size = 1;
1805 else if( size > 8 )
1806 size = 8;
1807 for(;;){
1808 if (!mnoread)
1809 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001810 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 if (!mnoread) {
1812 if (brev)
1813 byterev(val, size);
1814 putchar(' ');
1815 for (i = 0; i < n; ++i)
1816 printf("%.2x", val[i]);
1817 for (; i < size; ++i)
1818 printf("%s", fault_chars[fault_type]);
1819 }
1820 putchar(' ');
1821 inc = size;
1822 nslash = 0;
1823 for(;;){
1824 if( scanhex(&n) ){
1825 for (i = 0; i < size; ++i)
1826 val[i] = n >> (i * 8);
1827 if (!brev)
1828 byterev(val, size);
1829 mwrite(adrs, val, size);
1830 inc = size;
1831 }
1832 cmd = skipbl();
1833 if (cmd == '\n')
1834 break;
1835 inc = 0;
1836 switch (cmd) {
1837 case '\'':
1838 for(;;){
1839 n = inchar();
1840 if( n == '\\' )
1841 n = bsesc();
1842 else if( n == '\'' )
1843 break;
1844 for (i = 0; i < size; ++i)
1845 val[i] = n >> (i * 8);
1846 if (!brev)
1847 byterev(val, size);
1848 mwrite(adrs, val, size);
1849 adrs += size;
1850 }
1851 adrs -= size;
1852 inc = size;
1853 break;
1854 case ',':
1855 adrs += size;
1856 break;
1857 case '.':
1858 mnoread = 0;
1859 break;
1860 case ';':
1861 break;
1862 case 'x':
1863 case EOF:
1864 scannl();
1865 return;
1866 case 'b':
1867 case 'v':
1868 size = 1;
1869 break;
1870 case 'w':
1871 size = 2;
1872 break;
1873 case 'l':
1874 size = 4;
1875 break;
1876 case 'u':
1877 size = 8;
1878 break;
1879 case '^':
1880 adrs -= size;
1881 break;
1882 break;
1883 case '/':
1884 if (nslash > 0)
1885 adrs -= 1 << nslash;
1886 else
1887 nslash = 0;
1888 nslash += 4;
1889 adrs += 1 << nslash;
1890 break;
1891 case '\\':
1892 if (nslash < 0)
1893 adrs += 1 << -nslash;
1894 else
1895 nslash = 0;
1896 nslash -= 4;
1897 adrs -= 1 << -nslash;
1898 break;
1899 case 'm':
1900 scanhex((void *)&adrs);
1901 break;
1902 case 'n':
1903 mnoread = 1;
1904 break;
1905 case 'r':
1906 brev = !brev;
1907 break;
1908 case '<':
1909 n = size;
1910 scanhex(&n);
1911 adrs -= n;
1912 break;
1913 case '>':
1914 n = size;
1915 scanhex(&n);
1916 adrs += n;
1917 break;
1918 case '?':
1919 printf(memex_subcmd_help_string);
1920 break;
1921 }
1922 }
1923 adrs += inc;
1924 }
1925}
1926
1927int
1928bsesc(void)
1929{
1930 int c;
1931
1932 c = inchar();
1933 switch( c ){
1934 case 'n': c = '\n'; break;
1935 case 'r': c = '\r'; break;
1936 case 'b': c = '\b'; break;
1937 case 't': c = '\t'; break;
1938 }
1939 return c;
1940}
1941
Olaf Hering7e5b5932006-03-08 20:40:28 +01001942static void xmon_rawdump (unsigned long adrs, long ndump)
1943{
1944 long n, m, r, nr;
1945 unsigned char temp[16];
1946
1947 for (n = ndump; n > 0;) {
1948 r = n < 16? n: 16;
1949 nr = mread(adrs, temp, r);
1950 adrs += nr;
1951 for (m = 0; m < r; ++m) {
1952 if (m < nr)
1953 printf("%.2x", temp[m]);
1954 else
1955 printf("%s", fault_chars[fault_type]);
1956 }
1957 n -= r;
1958 if (nr < r)
1959 break;
1960 }
1961 printf("\n");
1962}
1963
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
1965 || ('a' <= (c) && (c) <= 'f') \
1966 || ('A' <= (c) && (c) <= 'F'))
1967void
1968dump(void)
1969{
1970 int c;
1971
1972 c = inchar();
1973 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1974 termch = c;
1975 scanhex((void *)&adrs);
1976 if (termch != '\n')
1977 termch = 0;
1978 if (c == 'i') {
1979 scanhex(&nidump);
1980 if (nidump == 0)
1981 nidump = 16;
1982 else if (nidump > MAX_DUMP)
1983 nidump = MAX_DUMP;
1984 adrs += ppc_inst_dump(adrs, nidump, 1);
1985 last_cmd = "di\n";
Olaf Hering7e5b5932006-03-08 20:40:28 +01001986 } else if (c == 'r') {
1987 scanhex(&ndump);
1988 if (ndump == 0)
1989 ndump = 64;
1990 xmon_rawdump(adrs, ndump);
1991 adrs += ndump;
1992 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 } else {
1994 scanhex(&ndump);
1995 if (ndump == 0)
1996 ndump = 64;
1997 else if (ndump > MAX_DUMP)
1998 ndump = MAX_DUMP;
1999 prdump(adrs, ndump);
2000 adrs += ndump;
2001 last_cmd = "d\n";
2002 }
2003}
2004
2005void
2006prdump(unsigned long adrs, long ndump)
2007{
2008 long n, m, c, r, nr;
2009 unsigned char temp[16];
2010
2011 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002012 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 putchar(' ');
2014 r = n < 16? n: 16;
2015 nr = mread(adrs, temp, r);
2016 adrs += nr;
2017 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002018 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2019 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 if (m < nr)
2021 printf("%.2x", temp[m]);
2022 else
2023 printf("%s", fault_chars[fault_type]);
2024 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002025 for (; m < 16; ++m) {
2026 if ((m & (sizeof(long) - 1)) == 0)
2027 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 printf(" |");
2031 for (m = 0; m < r; ++m) {
2032 if (m < nr) {
2033 c = temp[m];
2034 putchar(' ' <= c && c <= '~'? c: '.');
2035 } else
2036 putchar(' ');
2037 }
2038 n -= r;
2039 for (; m < 16; ++m)
2040 putchar(' ');
2041 printf("|\n");
2042 if (nr < r)
2043 break;
2044 }
2045}
2046
2047int
2048ppc_inst_dump(unsigned long adr, long count, int praddr)
2049{
2050 int nr, dotted;
2051 unsigned long first_adr;
2052 unsigned long inst, last_inst = 0;
2053 unsigned char val[4];
2054
2055 dotted = 0;
2056 for (first_adr = adr; count > 0; --count, adr += 4) {
2057 nr = mread(adr, val, 4);
2058 if (nr == 0) {
2059 if (praddr) {
2060 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002061 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 }
2063 break;
2064 }
2065 inst = GETWORD(val);
2066 if (adr > first_adr && inst == last_inst) {
2067 if (!dotted) {
2068 printf(" ...\n");
2069 dotted = 1;
2070 }
2071 continue;
2072 }
2073 dotted = 0;
2074 last_inst = inst;
2075 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002076 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 printf("\t");
2078 print_insn_powerpc(inst, adr, 0); /* always returns 4 */
2079 printf("\n");
2080 }
2081 return adr - first_adr;
2082}
2083
2084void
2085print_address(unsigned long addr)
2086{
2087 xmon_print_symbol(addr, "\t# ", "");
2088}
2089
2090
2091/*
2092 * Memory operations - move, set, print differences
2093 */
2094static unsigned long mdest; /* destination address */
2095static unsigned long msrc; /* source address */
2096static unsigned long mval; /* byte value to set memory to */
2097static unsigned long mcount; /* # bytes to affect */
2098static unsigned long mdiffs; /* max # differences to print */
2099
2100void
2101memops(int cmd)
2102{
2103 scanhex((void *)&mdest);
2104 if( termch != '\n' )
2105 termch = 0;
2106 scanhex((void *)(cmd == 's'? &mval: &msrc));
2107 if( termch != '\n' )
2108 termch = 0;
2109 scanhex((void *)&mcount);
2110 switch( cmd ){
2111 case 'm':
2112 memmove((void *)mdest, (void *)msrc, mcount);
2113 break;
2114 case 's':
2115 memset((void *)mdest, mval, mcount);
2116 break;
2117 case 'd':
2118 if( termch != '\n' )
2119 termch = 0;
2120 scanhex((void *)&mdiffs);
2121 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2122 break;
2123 }
2124}
2125
2126void
2127memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2128{
2129 unsigned n, prt;
2130
2131 prt = 0;
2132 for( n = nb; n > 0; --n )
2133 if( *p1++ != *p2++ )
2134 if( ++prt <= maxpr )
2135 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2136 p1[-1], p2 - 1, p2[-1]);
2137 if( prt > maxpr )
2138 printf("Total of %d differences\n", prt);
2139}
2140
2141static unsigned mend;
2142static unsigned mask;
2143
2144void
2145memlocate(void)
2146{
2147 unsigned a, n;
2148 unsigned char val[4];
2149
2150 last_cmd = "ml";
2151 scanhex((void *)&mdest);
2152 if (termch != '\n') {
2153 termch = 0;
2154 scanhex((void *)&mend);
2155 if (termch != '\n') {
2156 termch = 0;
2157 scanhex((void *)&mval);
2158 mask = ~0;
2159 if (termch != '\n') termch = 0;
2160 scanhex((void *)&mask);
2161 }
2162 }
2163 n = 0;
2164 for (a = mdest; a < mend; a += 4) {
2165 if (mread(a, val, 4) == 4
2166 && ((GETWORD(val) ^ mval) & mask) == 0) {
2167 printf("%.16x: %.16x\n", a, GETWORD(val));
2168 if (++n >= 10)
2169 break;
2170 }
2171 }
2172}
2173
2174static unsigned long mskip = 0x1000;
2175static unsigned long mlim = 0xffffffff;
2176
2177void
2178memzcan(void)
2179{
2180 unsigned char v;
2181 unsigned a;
2182 int ok, ook;
2183
2184 scanhex(&mdest);
2185 if (termch != '\n') termch = 0;
2186 scanhex(&mskip);
2187 if (termch != '\n') termch = 0;
2188 scanhex(&mlim);
2189 ook = 0;
2190 for (a = mdest; a < mlim; a += mskip) {
2191 ok = mread(a, &v, 1);
2192 if (ok && !ook) {
2193 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 } else if (!ok && ook)
2195 printf("%.8x\n", a - mskip);
2196 ook = ok;
2197 if (a + mskip < a)
2198 break;
2199 }
2200 if (ook)
2201 printf("%.8x\n", a - mskip);
2202}
2203
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002204void proccall(void)
2205{
2206 unsigned long args[8];
2207 unsigned long ret;
2208 int i;
2209 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2210 unsigned long, unsigned long, unsigned long,
2211 unsigned long, unsigned long, unsigned long);
2212 callfunc_t func;
2213
2214 if (!scanhex(&adrs))
2215 return;
2216 if (termch != '\n')
2217 termch = 0;
2218 for (i = 0; i < 8; ++i)
2219 args[i] = 0;
2220 for (i = 0; i < 8; ++i) {
2221 if (!scanhex(&args[i]) || termch == '\n')
2222 break;
2223 termch = 0;
2224 }
2225 func = (callfunc_t) adrs;
2226 ret = 0;
2227 if (setjmp(bus_error_jmp) == 0) {
2228 catch_memory_errors = 1;
2229 sync();
2230 ret = func(args[0], args[1], args[2], args[3],
2231 args[4], args[5], args[6], args[7]);
2232 sync();
2233 printf("return value is %x\n", ret);
2234 } else {
2235 printf("*** %x exception occurred\n", fault_except);
2236 }
2237 catch_memory_errors = 0;
2238}
2239
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240/* Input scanning routines */
2241int
2242skipbl(void)
2243{
2244 int c;
2245
2246 if( termch != 0 ){
2247 c = termch;
2248 termch = 0;
2249 } else
2250 c = inchar();
2251 while( c == ' ' || c == '\t' )
2252 c = inchar();
2253 return c;
2254}
2255
2256#define N_PTREGS 44
2257static char *regnames[N_PTREGS] = {
2258 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2259 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2260 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2261 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002262 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2263#ifdef CONFIG_PPC64
2264 "softe",
2265#else
2266 "mq",
2267#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 "trap", "dar", "dsisr", "res"
2269};
2270
2271int
2272scanhex(unsigned long *vp)
2273{
2274 int c, d;
2275 unsigned long v;
2276
2277 c = skipbl();
2278 if (c == '%') {
2279 /* parse register name */
2280 char regname[8];
2281 int i;
2282
2283 for (i = 0; i < sizeof(regname) - 1; ++i) {
2284 c = inchar();
2285 if (!isalnum(c)) {
2286 termch = c;
2287 break;
2288 }
2289 regname[i] = c;
2290 }
2291 regname[i] = 0;
2292 for (i = 0; i < N_PTREGS; ++i) {
2293 if (strcmp(regnames[i], regname) == 0) {
2294 if (xmon_regs == NULL) {
2295 printf("regs not available\n");
2296 return 0;
2297 }
2298 *vp = ((unsigned long *)xmon_regs)[i];
2299 return 1;
2300 }
2301 }
2302 printf("invalid register name '%%%s'\n", regname);
2303 return 0;
2304 }
2305
2306 /* skip leading "0x" if any */
2307
2308 if (c == '0') {
2309 c = inchar();
2310 if (c == 'x') {
2311 c = inchar();
2312 } else {
2313 d = hexdigit(c);
2314 if (d == EOF) {
2315 termch = c;
2316 *vp = 0;
2317 return 1;
2318 }
2319 }
2320 } else if (c == '$') {
2321 int i;
2322 for (i=0; i<63; i++) {
2323 c = inchar();
2324 if (isspace(c)) {
2325 termch = c;
2326 break;
2327 }
2328 tmpstr[i] = c;
2329 }
2330 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002331 *vp = 0;
2332 if (setjmp(bus_error_jmp) == 0) {
2333 catch_memory_errors = 1;
2334 sync();
2335 *vp = kallsyms_lookup_name(tmpstr);
2336 sync();
2337 }
2338 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 if (!(*vp)) {
2340 printf("unknown symbol '%s'\n", tmpstr);
2341 return 0;
2342 }
2343 return 1;
2344 }
2345
2346 d = hexdigit(c);
2347 if (d == EOF) {
2348 termch = c;
2349 return 0;
2350 }
2351 v = 0;
2352 do {
2353 v = (v << 4) + d;
2354 c = inchar();
2355 d = hexdigit(c);
2356 } while (d != EOF);
2357 termch = c;
2358 *vp = v;
2359 return 1;
2360}
2361
2362void
2363scannl(void)
2364{
2365 int c;
2366
2367 c = termch;
2368 termch = 0;
2369 while( c != '\n' )
2370 c = inchar();
2371}
2372
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002373int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374{
2375 if( '0' <= c && c <= '9' )
2376 return c - '0';
2377 if( 'A' <= c && c <= 'F' )
2378 return c - ('A' - 10);
2379 if( 'a' <= c && c <= 'f' )
2380 return c - ('a' - 10);
2381 return EOF;
2382}
2383
2384void
2385getstring(char *s, int size)
2386{
2387 int c;
2388
2389 c = skipbl();
2390 do {
2391 if( size > 1 ){
2392 *s++ = c;
2393 --size;
2394 }
2395 c = inchar();
2396 } while( c != ' ' && c != '\t' && c != '\n' );
2397 termch = c;
2398 *s = 0;
2399}
2400
2401static char line[256];
2402static char *lineptr;
2403
2404void
2405flush_input(void)
2406{
2407 lineptr = NULL;
2408}
2409
2410int
2411inchar(void)
2412{
2413 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002414 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 lineptr = NULL;
2416 return EOF;
2417 }
2418 lineptr = line;
2419 }
2420 return *lineptr++;
2421}
2422
2423void
2424take_input(char *str)
2425{
2426 lineptr = str;
2427}
2428
2429
2430static void
2431symbol_lookup(void)
2432{
2433 int type = inchar();
2434 unsigned long addr;
2435 static char tmp[64];
2436
2437 switch (type) {
2438 case 'a':
2439 if (scanhex(&addr))
2440 xmon_print_symbol(addr, ": ", "\n");
2441 termch = 0;
2442 break;
2443 case 's':
2444 getstring(tmp, 64);
2445 if (setjmp(bus_error_jmp) == 0) {
2446 catch_memory_errors = 1;
2447 sync();
2448 addr = kallsyms_lookup_name(tmp);
2449 if (addr)
2450 printf("%s: %lx\n", tmp, addr);
2451 else
2452 printf("Symbol '%s' not found.\n", tmp);
2453 sync();
2454 }
2455 catch_memory_errors = 0;
2456 termch = 0;
2457 break;
2458 }
2459}
2460
2461
2462/* Print an address in numeric and symbolic form (if possible) */
2463static void xmon_print_symbol(unsigned long address, const char *mid,
2464 const char *after)
2465{
2466 char *modname;
2467 const char *name = NULL;
2468 unsigned long offset, size;
2469
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002470 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 if (setjmp(bus_error_jmp) == 0) {
2472 catch_memory_errors = 1;
2473 sync();
2474 name = kallsyms_lookup(address, &size, &offset, &modname,
2475 tmpstr);
2476 sync();
2477 /* wait a little while to see if we get a machine check */
2478 __delay(200);
2479 }
2480
2481 catch_memory_errors = 0;
2482
2483 if (name) {
2484 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2485 if (modname)
2486 printf(" [%s]", modname);
2487 }
2488 printf("%s", after);
2489}
2490
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002491#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492static void dump_slb(void)
2493{
2494 int i;
2495 unsigned long tmp;
2496
2497 printf("SLB contents of cpu %x\n", smp_processor_id());
2498
2499 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2500 asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
2501 printf("%02d %016lx ", i, tmp);
2502
2503 asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
2504 printf("%016lx\n", tmp);
2505 }
2506}
2507
2508static void dump_stab(void)
2509{
2510 int i;
2511 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2512
2513 printf("Segment table contents of cpu %x\n", smp_processor_id());
2514
2515 for (i = 0; i < PAGE_SIZE/16; i++) {
2516 unsigned long a, b;
2517
2518 a = *tmp++;
2519 b = *tmp++;
2520
2521 if (a || b) {
2522 printf("%03d %016lx ", i, a);
2523 printf("%016lx\n", b);
2524 }
2525 }
2526}
2527
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002528void dump_segments(void)
2529{
2530 if (cpu_has_feature(CPU_FTR_SLB))
2531 dump_slb();
2532 else
2533 dump_stab();
2534}
2535#endif
2536
2537#ifdef CONFIG_PPC_STD_MMU_32
2538void dump_segments(void)
2539{
2540 int i;
2541
2542 printf("sr0-15 =");
2543 for (i = 0; i < 16; ++i)
2544 printf(" %x", mfsrin(i));
2545 printf("\n");
2546}
2547#endif
2548
Olaf Heringb13cfd12005-08-04 19:26:42 +02002549void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550{
Olaf Heringb13cfd12005-08-04 19:26:42 +02002551 if (enable) {
2552 __debugger = xmon;
2553 __debugger_ipi = xmon_ipi;
2554 __debugger_bpt = xmon_bpt;
2555 __debugger_sstep = xmon_sstep;
2556 __debugger_iabr_match = xmon_iabr_match;
2557 __debugger_dabr_match = xmon_dabr_match;
2558 __debugger_fault_handler = xmon_fault_handler;
2559 } else {
2560 __debugger = NULL;
2561 __debugger_ipi = NULL;
2562 __debugger_bpt = NULL;
2563 __debugger_sstep = NULL;
2564 __debugger_iabr_match = NULL;
2565 __debugger_dabr_match = NULL;
2566 __debugger_fault_handler = NULL;
2567 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002568 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002570
2571#ifdef CONFIG_MAGIC_SYSRQ
2572static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
2573 struct tty_struct *tty)
2574{
2575 /* ensure xmon is enabled */
2576 xmon_init(1);
2577 debugger(pt_regs);
2578}
2579
2580static struct sysrq_key_op sysrq_xmon_op =
2581{
2582 .handler = sysrq_handle_xmon,
2583 .help_msg = "Xmon",
2584 .action_msg = "Entering xmon",
2585};
2586
2587static int __init setup_xmon_sysrq(void)
2588{
2589 register_sysrq_key('x', &sysrq_xmon_op);
2590 return 0;
2591}
2592__initcall(setup_xmon_sysrq);
2593#endif /* CONFIG_MAGIC_SYSRQ */