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