blob: 22612ed5379c46d0c0482759f873261298522d91 [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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-10-28 22:53:37 +100040
41#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-10-28 22:53:37 +1000149
150extern void xmon_enter(void);
151extern void xmon_leave(void);
152
Paul Mackerrasf78541dc2005-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\
194 e print exception information\n\
195 f flush cache\n\
196 la lookup symbol+offset of specified address\n\
197 ls lookup address of specified symbol\n\
198 m examine/change memory\n\
199 mm move a block of memory\n\
200 ms set a block of memory\n\
201 md compare two blocks of memory\n\
202 ml locate a block of memory\n\
203 mz zero a block of memory\n\
204 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000205 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 r print registers\n\
207 s single step\n\
208 S print special registers\n\
209 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000211 X exit monitor and dont recover\n"
212#ifdef CONFIG_PPC64
213" u dump segment table or SLB\n"
214#endif
215#ifdef CONFIG_PPC_STD_MMU_32
216" u dump segment registers\n"
217#endif
218" ? help\n"
219" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 zh halt\n"
221;
222
223static struct pt_regs *xmon_regs;
224
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000225static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
227 asm volatile("sync; isync");
228}
229
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000230static inline void store_inst(void *p)
231{
232 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
233}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000235static inline void cflush(void *p)
236{
237 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
238}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000240static inline void cinval(void *p)
241{
242 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
243}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245/*
246 * Disable surveillance (the service processor watchdog function)
247 * while we are in xmon.
248 * XXX we should re-enable it when we leave. :)
249 */
250#define SURVEILLANCE_TOKEN 9000
251
252static inline void disable_surveillance(void)
253{
254#ifdef CONFIG_PPC_PSERIES
255 /* Since this can't be a module, args should end up below 4GB. */
256 static struct rtas_args args;
257
258 /*
259 * At this point we have got all the cpus we can into
260 * xmon, so there is hopefully no other cpu calling RTAS
261 * at the moment, even though we don't take rtas.lock.
262 * If we did try to take rtas.lock there would be a
263 * real possibility of deadlock.
264 */
265 args.token = rtas_token("set-indicator");
266 if (args.token == RTAS_UNKNOWN_SERVICE)
267 return;
268 args.nargs = 3;
269 args.nret = 1;
270 args.rets = &args.args[3];
271 args.args[0] = SURVEILLANCE_TOKEN;
272 args.args[1] = 0;
273 args.args[2] = 0;
274 enter_rtas(__pa(&args));
275#endif /* CONFIG_PPC_PSERIES */
276}
277
278#ifdef CONFIG_SMP
279static int xmon_speaker;
280
281static void get_output_lock(void)
282{
283 int me = smp_processor_id() + 0x100;
284 int last_speaker = 0, prev;
285 long timeout;
286
287 if (xmon_speaker == me)
288 return;
289 for (;;) {
290 if (xmon_speaker == 0) {
291 last_speaker = cmpxchg(&xmon_speaker, 0, me);
292 if (last_speaker == 0)
293 return;
294 }
295 timeout = 10000000;
296 while (xmon_speaker == last_speaker) {
297 if (--timeout > 0)
298 continue;
299 /* hostile takeover */
300 prev = cmpxchg(&xmon_speaker, last_speaker, me);
301 if (prev == last_speaker)
302 return;
303 break;
304 }
305 }
306}
307
308static void release_output_lock(void)
309{
310 xmon_speaker = 0;
311}
312#endif
313
314int xmon_core(struct pt_regs *regs, int fromipi)
315{
316 int cmd = 0;
317 unsigned long msr;
318 struct bpt *bp;
319 long recurse_jmp[JMP_BUF_LEN];
320 unsigned long offset;
321#ifdef CONFIG_SMP
322 int cpu;
323 int secondary;
324 unsigned long timeout;
325#endif
326
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000327 msr = mfmsr();
328 mtmsr(msr & ~MSR_EE); /* disable interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 bp = in_breakpoint_table(regs->nip, &offset);
331 if (bp != NULL) {
332 regs->nip = bp->address + offset;
333 atomic_dec(&bp->ref_count);
334 }
335
336 remove_cpu_bpts();
337
338#ifdef CONFIG_SMP
339 cpu = smp_processor_id();
340 if (cpu_isset(cpu, cpus_in_xmon)) {
341 get_output_lock();
342 excprint(regs);
343 printf("cpu 0x%x: Exception %lx %s in xmon, "
344 "returning to main loop\n",
345 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000346 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 longjmp(xmon_fault_jmp[cpu], 1);
348 }
349
350 if (setjmp(recurse_jmp) != 0) {
351 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000352 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 printf("xmon: WARNING: bad recursive fault "
354 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000355 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 goto waiting;
357 }
358 secondary = !(xmon_taken && cpu == xmon_owner);
359 goto cmdloop;
360 }
361
362 xmon_fault_jmp[cpu] = recurse_jmp;
363 cpu_set(cpu, cpus_in_xmon);
364
365 bp = NULL;
366 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
367 bp = at_breakpoint(regs->nip);
368 if (bp || (regs->msr & MSR_RI) == 0)
369 fromipi = 0;
370
371 if (!fromipi) {
372 get_output_lock();
373 excprint(regs);
374 if (bp) {
375 printf("cpu 0x%x stopped at breakpoint 0x%x (",
376 cpu, BP_NUM(bp));
377 xmon_print_symbol(regs->nip, " ", ")\n");
378 }
379 if ((regs->msr & MSR_RI) == 0)
380 printf("WARNING: exception is not recoverable, "
381 "can't continue\n");
382 release_output_lock();
383 }
384
385 waiting:
386 secondary = 1;
387 while (secondary && !xmon_gate) {
388 if (in_xmon == 0) {
389 if (fromipi)
390 goto leave;
391 secondary = test_and_set_bit(0, &in_xmon);
392 }
393 barrier();
394 }
395
396 if (!secondary && !xmon_gate) {
397 /* we are the first cpu to come in */
398 /* interrupt other cpu(s) */
399 int ncpus = num_online_cpus();
400
401 xmon_owner = cpu;
402 mb();
403 if (ncpus > 1) {
404 smp_send_debugger_break(MSG_ALL_BUT_SELF);
405 /* wait for other cpus to come in */
406 for (timeout = 100000000; timeout != 0; --timeout) {
407 if (cpus_weight(cpus_in_xmon) >= ncpus)
408 break;
409 barrier();
410 }
411 }
412 remove_bpts();
413 disable_surveillance();
414 /* for breakpoint or single step, print the current instr. */
415 if (bp || TRAP(regs) == 0xd00)
416 ppc_inst_dump(regs->nip, 1, 0);
417 printf("enter ? for help\n");
418 mb();
419 xmon_gate = 1;
420 barrier();
421 }
422
423 cmdloop:
424 while (in_xmon) {
425 if (secondary) {
426 if (cpu == xmon_owner) {
427 if (!test_and_set_bit(0, &xmon_taken)) {
428 secondary = 0;
429 continue;
430 }
431 /* missed it */
432 while (cpu == xmon_owner)
433 barrier();
434 }
435 barrier();
436 } else {
437 cmd = cmds(regs);
438 if (cmd != 0) {
439 /* exiting xmon */
440 insert_bpts();
441 xmon_gate = 0;
442 wmb();
443 in_xmon = 0;
444 break;
445 }
446 /* have switched to some other cpu */
447 secondary = 1;
448 }
449 }
450 leave:
451 cpu_clear(cpu, cpus_in_xmon);
452 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453#else
454 /* UP is simple... */
455 if (in_xmon) {
456 printf("Exception %lx %s in xmon, returning to main loop\n",
457 regs->trap, getvecname(TRAP(regs)));
458 longjmp(xmon_fault_jmp[0], 1);
459 }
460 if (setjmp(recurse_jmp) == 0) {
461 xmon_fault_jmp[0] = recurse_jmp;
462 in_xmon = 1;
463
464 excprint(regs);
465 bp = at_breakpoint(regs->nip);
466 if (bp) {
467 printf("Stopped at breakpoint %x (", BP_NUM(bp));
468 xmon_print_symbol(regs->nip, " ", ")\n");
469 }
470 if ((regs->msr & MSR_RI) == 0)
471 printf("WARNING: exception is not recoverable, "
472 "can't continue\n");
473 remove_bpts();
474 disable_surveillance();
475 /* for breakpoint or single step, print the current instr. */
476 if (bp || TRAP(regs) == 0xd00)
477 ppc_inst_dump(regs->nip, 1, 0);
478 printf("enter ? for help\n");
479 }
480
481 cmd = cmds(regs);
482
483 insert_bpts();
484 in_xmon = 0;
485#endif
486
487 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
488 bp = at_breakpoint(regs->nip);
489 if (bp != NULL) {
490 int stepped = emulate_step(regs, bp->instr[0]);
491 if (stepped == 0) {
492 regs->nip = (unsigned long) &bp->instr[0];
493 atomic_inc(&bp->ref_count);
494 } else if (stepped < 0) {
495 printf("Couldn't single-step %s instruction\n",
496 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
497 }
498 }
499 }
500
501 insert_cpu_bpts();
502
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000503 mtmsr(msr); /* restore interrupt enable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 return cmd != 'X';
506}
507
508int xmon(struct pt_regs *excp)
509{
510 struct pt_regs regs;
511
512 if (excp == NULL) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000513 xmon_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 excp = &regs;
515 }
516 return xmon_core(excp, 0);
517}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000518EXPORT_SYMBOL(xmon);
519
520irqreturn_t
521xmon_irq(int irq, void *d, struct pt_regs *regs)
522{
523 unsigned long flags;
524 local_irq_save(flags);
525 printf("Keyboard interrupt\n");
526 xmon(regs);
527 local_irq_restore(flags);
528 return IRQ_HANDLED;
529}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531int xmon_bpt(struct pt_regs *regs)
532{
533 struct bpt *bp;
534 unsigned long offset;
535
536 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
537 return 0;
538
539 /* Are we at the trap at bp->instr[1] for some bp? */
540 bp = in_breakpoint_table(regs->nip, &offset);
541 if (bp != NULL && offset == 4) {
542 regs->nip = bp->address + 4;
543 atomic_dec(&bp->ref_count);
544 return 1;
545 }
546
547 /* Are we at a breakpoint? */
548 bp = at_breakpoint(regs->nip);
549 if (!bp)
550 return 0;
551
552 xmon_core(regs, 0);
553
554 return 1;
555}
556
557int xmon_sstep(struct pt_regs *regs)
558{
559 if (user_mode(regs))
560 return 0;
561 xmon_core(regs, 0);
562 return 1;
563}
564
565int xmon_dabr_match(struct pt_regs *regs)
566{
567 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
568 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000569 if (dabr.enabled == 0)
570 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 xmon_core(regs, 0);
572 return 1;
573}
574
575int xmon_iabr_match(struct pt_regs *regs)
576{
577 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
578 return 0;
579 if (iabr == 0)
580 return 0;
581 xmon_core(regs, 0);
582 return 1;
583}
584
585int xmon_ipi(struct pt_regs *regs)
586{
587#ifdef CONFIG_SMP
588 if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
589 xmon_core(regs, 1);
590#endif
591 return 0;
592}
593
594int xmon_fault_handler(struct pt_regs *regs)
595{
596 struct bpt *bp;
597 unsigned long offset;
598
599 if (in_xmon && catch_memory_errors)
600 handle_fault(regs); /* doesn't return */
601
602 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
603 bp = in_breakpoint_table(regs->nip, &offset);
604 if (bp != NULL) {
605 regs->nip = bp->address + offset;
606 atomic_dec(&bp->ref_count);
607 }
608 }
609
610 return 0;
611}
612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613static struct bpt *at_breakpoint(unsigned long pc)
614{
615 int i;
616 struct bpt *bp;
617
618 bp = bpts;
619 for (i = 0; i < NBPTS; ++i, ++bp)
620 if (bp->enabled && pc == bp->address)
621 return bp;
622 return NULL;
623}
624
625static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
626{
627 unsigned long off;
628
629 off = nip - (unsigned long) bpts;
630 if (off >= sizeof(bpts))
631 return NULL;
632 off %= sizeof(struct bpt);
633 if (off != offsetof(struct bpt, instr[0])
634 && off != offsetof(struct bpt, instr[1]))
635 return NULL;
636 *offp = off - offsetof(struct bpt, instr[0]);
637 return (struct bpt *) (nip - off);
638}
639
640static struct bpt *new_breakpoint(unsigned long a)
641{
642 struct bpt *bp;
643
644 a &= ~3UL;
645 bp = at_breakpoint(a);
646 if (bp)
647 return bp;
648
649 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
650 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
651 bp->address = a;
652 bp->instr[1] = bpinstr;
653 store_inst(&bp->instr[1]);
654 return bp;
655 }
656 }
657
658 printf("Sorry, no free breakpoints. Please clear one first.\n");
659 return NULL;
660}
661
662static void insert_bpts(void)
663{
664 int i;
665 struct bpt *bp;
666
667 bp = bpts;
668 for (i = 0; i < NBPTS; ++i, ++bp) {
669 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
670 continue;
671 if (mread(bp->address, &bp->instr[0], 4) != 4) {
672 printf("Couldn't read instruction at %lx, "
673 "disabling breakpoint there\n", bp->address);
674 bp->enabled = 0;
675 continue;
676 }
677 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
678 printf("Breakpoint at %lx is on an mtmsrd or rfid "
679 "instruction, disabling it\n", bp->address);
680 bp->enabled = 0;
681 continue;
682 }
683 store_inst(&bp->instr[0]);
684 if (bp->enabled & BP_IABR)
685 continue;
686 if (mwrite(bp->address, &bpinstr, 4) != 4) {
687 printf("Couldn't write instruction at %lx, "
688 "disabling breakpoint there\n", bp->address);
689 bp->enabled &= ~BP_TRAP;
690 continue;
691 }
692 store_inst((void *)bp->address);
693 }
694}
695
696static void insert_cpu_bpts(void)
697{
698 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000699 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000701 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
703}
704
705static void remove_bpts(void)
706{
707 int i;
708 struct bpt *bp;
709 unsigned instr;
710
711 bp = bpts;
712 for (i = 0; i < NBPTS; ++i, ++bp) {
713 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
714 continue;
715 if (mread(bp->address, &instr, 4) == 4
716 && instr == bpinstr
717 && mwrite(bp->address, &bp->instr, 4) != 4)
718 printf("Couldn't remove breakpoint at %lx\n",
719 bp->address);
720 else
721 store_inst((void *)bp->address);
722 }
723}
724
725static void remove_cpu_bpts(void)
726{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000727 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000729 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730}
731
732/* Command interpreting routine */
733static char *last_cmd;
734
735static int
736cmds(struct pt_regs *excp)
737{
738 int cmd = 0;
739
740 last_cmd = NULL;
741 xmon_regs = excp;
742 for(;;) {
743#ifdef CONFIG_SMP
744 printf("%x:", smp_processor_id());
745#endif /* CONFIG_SMP */
746 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 flush_input();
748 termch = 0;
749 cmd = skipbl();
750 if( cmd == '\n' ) {
751 if (last_cmd == NULL)
752 continue;
753 take_input(last_cmd);
754 last_cmd = NULL;
755 cmd = inchar();
756 }
757 switch (cmd) {
758 case 'm':
759 cmd = inchar();
760 switch (cmd) {
761 case 'm':
762 case 's':
763 case 'd':
764 memops(cmd);
765 break;
766 case 'l':
767 memlocate();
768 break;
769 case 'z':
770 memzcan();
771 break;
772 case 'i':
773 show_mem();
774 break;
775 default:
776 termch = cmd;
777 memex();
778 }
779 break;
780 case 'd':
781 dump();
782 break;
783 case 'l':
784 symbol_lookup();
785 break;
786 case 'r':
787 prregs(excp); /* print regs */
788 break;
789 case 'e':
790 excprint(excp);
791 break;
792 case 'S':
793 super_regs();
794 break;
795 case 't':
796 backtrace(excp);
797 break;
798 case 'f':
799 cacheflush();
800 break;
801 case 's':
802 if (do_step(excp))
803 return cmd;
804 break;
805 case 'x':
806 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100807 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100809 printf(" <no input ...>\n");
810 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return cmd;
812 case '?':
813 printf(help_string);
814 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 case 'b':
816 bpt_cmds();
817 break;
818 case 'C':
819 csum();
820 break;
821 case 'c':
822 if (cpu_cmd())
823 return 0;
824 break;
825 case 'z':
826 bootcmds();
827 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000828 case 'p':
829 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000831#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 case 'u':
833 dump_segments();
834 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000835#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 default:
837 printf("Unrecognized command: ");
838 do {
839 if (' ' < cmd && cmd <= '~')
840 putchar(cmd);
841 else
842 printf("\\x%x", cmd);
843 cmd = inchar();
844 } while (cmd != '\n');
845 printf(" (type ? for help)\n");
846 break;
847 }
848 }
849}
850
851/*
852 * Step a single instruction.
853 * Some instructions we emulate, others we execute with MSR_SE set.
854 */
855static int do_step(struct pt_regs *regs)
856{
857 unsigned int instr;
858 int stepped;
859
860 /* check we are in 64-bit kernel mode, translation enabled */
861 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
862 if (mread(regs->nip, &instr, 4) == 4) {
863 stepped = emulate_step(regs, instr);
864 if (stepped < 0) {
865 printf("Couldn't single-step %s instruction\n",
866 (IS_RFID(instr)? "rfid": "mtmsrd"));
867 return 0;
868 }
869 if (stepped > 0) {
870 regs->trap = 0xd00 | (regs->trap & 1);
871 printf("stepped to ");
872 xmon_print_symbol(regs->nip, " ", "\n");
873 ppc_inst_dump(regs->nip, 1, 0);
874 return 0;
875 }
876 }
877 }
878 regs->msr |= MSR_SE;
879 return 1;
880}
881
882static void bootcmds(void)
883{
884 int cmd;
885
886 cmd = inchar();
887 if (cmd == 'r')
888 ppc_md.restart(NULL);
889 else if (cmd == 'h')
890 ppc_md.halt();
891 else if (cmd == 'p')
892 ppc_md.power_off();
893}
894
895static int cpu_cmd(void)
896{
897#ifdef CONFIG_SMP
898 unsigned long cpu;
899 int timeout;
900 int count;
901
902 if (!scanhex(&cpu)) {
903 /* print cpus waiting or in xmon */
904 printf("cpus stopped:");
905 count = 0;
906 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
907 if (cpu_isset(cpu, cpus_in_xmon)) {
908 if (count == 0)
909 printf(" %x", cpu);
910 ++count;
911 } else {
912 if (count > 1)
913 printf("-%x", cpu - 1);
914 count = 0;
915 }
916 }
917 if (count > 1)
918 printf("-%x", NR_CPUS - 1);
919 printf("\n");
920 return 0;
921 }
922 /* try to switch to cpu specified */
923 if (!cpu_isset(cpu, cpus_in_xmon)) {
924 printf("cpu 0x%x isn't in xmon\n", cpu);
925 return 0;
926 }
927 xmon_taken = 0;
928 mb();
929 xmon_owner = cpu;
930 timeout = 10000000;
931 while (!xmon_taken) {
932 if (--timeout == 0) {
933 if (test_and_set_bit(0, &xmon_taken))
934 break;
935 /* take control back */
936 mb();
937 xmon_owner = smp_processor_id();
938 printf("cpu %u didn't take control\n", cpu);
939 return 0;
940 }
941 barrier();
942 }
943 return 1;
944#else
945 return 0;
946#endif /* CONFIG_SMP */
947}
948
949static unsigned short fcstab[256] = {
950 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
951 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
952 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
953 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
954 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
955 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
956 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
957 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
958 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
959 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
960 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
961 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
962 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
963 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
964 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
965 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
966 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
967 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
968 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
969 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
970 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
971 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
972 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
973 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
974 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
975 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
976 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
977 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
978 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
979 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
980 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
981 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
982};
983
984#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
985
986static void
987csum(void)
988{
989 unsigned int i;
990 unsigned short fcs;
991 unsigned char v;
992
993 if (!scanhex(&adrs))
994 return;
995 if (!scanhex(&ncsum))
996 return;
997 fcs = 0xffff;
998 for (i = 0; i < ncsum; ++i) {
999 if (mread(adrs+i, &v, 1) == 0) {
1000 printf("csum stopped at %x\n", adrs+i);
1001 break;
1002 }
1003 fcs = FCS(fcs, v);
1004 }
1005 printf("%x\n", fcs);
1006}
1007
1008/*
1009 * Check if this is a suitable place to put a breakpoint.
1010 */
1011static long check_bp_loc(unsigned long addr)
1012{
1013 unsigned int instr;
1014
1015 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001016 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 printf("Breakpoints may only be placed at kernel addresses\n");
1018 return 0;
1019 }
1020 if (!mread(addr, &instr, sizeof(instr))) {
1021 printf("Can't read instruction at address %lx\n", addr);
1022 return 0;
1023 }
1024 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1025 printf("Breakpoints may not be placed on mtmsrd or rfid "
1026 "instructions\n");
1027 return 0;
1028 }
1029 return 1;
1030}
1031
1032static char *breakpoint_help_string =
1033 "Breakpoint command usage:\n"
1034 "b show breakpoints\n"
1035 "b <addr> [cnt] set breakpoint at given instr addr\n"
1036 "bc clear all breakpoints\n"
1037 "bc <n/addr> clear breakpoint number n or at addr\n"
1038 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1039 "bd <addr> [cnt] set hardware data breakpoint\n"
1040 "";
1041
1042static void
1043bpt_cmds(void)
1044{
1045 int cmd;
1046 unsigned long a;
1047 int mode, i;
1048 struct bpt *bp;
1049 const char badaddr[] = "Only kernel addresses are permitted "
1050 "for breakpoints\n";
1051
1052 cmd = inchar();
1053 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001054#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 case 'd': /* bd - hardware data breakpoint */
1056 mode = 7;
1057 cmd = inchar();
1058 if (cmd == 'r')
1059 mode = 5;
1060 else if (cmd == 'w')
1061 mode = 6;
1062 else
1063 termch = cmd;
1064 dabr.address = 0;
1065 dabr.enabled = 0;
1066 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001067 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 printf(badaddr);
1069 break;
1070 }
1071 dabr.address &= ~7;
1072 dabr.enabled = mode | BP_DABR;
1073 }
1074 break;
1075
1076 case 'i': /* bi - hardware instr breakpoint */
1077 if (!cpu_has_feature(CPU_FTR_IABR)) {
1078 printf("Hardware instruction breakpoint "
1079 "not supported on this cpu\n");
1080 break;
1081 }
1082 if (iabr) {
1083 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1084 iabr = NULL;
1085 }
1086 if (!scanhex(&a))
1087 break;
1088 if (!check_bp_loc(a))
1089 break;
1090 bp = new_breakpoint(a);
1091 if (bp != NULL) {
1092 bp->enabled |= BP_IABR | BP_IABR_TE;
1093 iabr = bp;
1094 }
1095 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001096#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
1098 case 'c':
1099 if (!scanhex(&a)) {
1100 /* clear all breakpoints */
1101 for (i = 0; i < NBPTS; ++i)
1102 bpts[i].enabled = 0;
1103 iabr = NULL;
1104 dabr.enabled = 0;
1105 printf("All breakpoints cleared\n");
1106 break;
1107 }
1108
1109 if (a <= NBPTS && a >= 1) {
1110 /* assume a breakpoint number */
1111 bp = &bpts[a-1]; /* bp nums are 1 based */
1112 } else {
1113 /* assume a breakpoint address */
1114 bp = at_breakpoint(a);
1115 if (bp == 0) {
1116 printf("No breakpoint at %x\n", a);
1117 break;
1118 }
1119 }
1120
1121 printf("Cleared breakpoint %x (", BP_NUM(bp));
1122 xmon_print_symbol(bp->address, " ", ")\n");
1123 bp->enabled = 0;
1124 break;
1125
1126 default:
1127 termch = cmd;
1128 cmd = skipbl();
1129 if (cmd == '?') {
1130 printf(breakpoint_help_string);
1131 break;
1132 }
1133 termch = cmd;
1134 if (!scanhex(&a)) {
1135 /* print all breakpoints */
1136 printf(" type address\n");
1137 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001138 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 if (dabr.enabled & 1)
1140 printf("r");
1141 if (dabr.enabled & 2)
1142 printf("w");
1143 printf("]\n");
1144 }
1145 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1146 if (!bp->enabled)
1147 continue;
1148 printf("%2x %s ", BP_NUM(bp),
1149 (bp->enabled & BP_IABR)? "inst": "trap");
1150 xmon_print_symbol(bp->address, " ", "\n");
1151 }
1152 break;
1153 }
1154
1155 if (!check_bp_loc(a))
1156 break;
1157 bp = new_breakpoint(a);
1158 if (bp != NULL)
1159 bp->enabled |= BP_TRAP;
1160 break;
1161 }
1162}
1163
1164/* Very cheap human name for vector lookup. */
1165static
1166const char *getvecname(unsigned long vec)
1167{
1168 char *ret;
1169
1170 switch (vec) {
1171 case 0x100: ret = "(System Reset)"; break;
1172 case 0x200: ret = "(Machine Check)"; break;
1173 case 0x300: ret = "(Data Access)"; break;
1174 case 0x380: ret = "(Data SLB Access)"; break;
1175 case 0x400: ret = "(Instruction Access)"; break;
1176 case 0x480: ret = "(Instruction SLB Access)"; break;
1177 case 0x500: ret = "(Hardware Interrupt)"; break;
1178 case 0x600: ret = "(Alignment)"; break;
1179 case 0x700: ret = "(Program Check)"; break;
1180 case 0x800: ret = "(FPU Unavailable)"; break;
1181 case 0x900: ret = "(Decrementer)"; break;
1182 case 0xc00: ret = "(System Call)"; break;
1183 case 0xd00: ret = "(Single Step)"; break;
1184 case 0xf00: ret = "(Performance Monitor)"; break;
1185 case 0xf20: ret = "(Altivec Unavailable)"; break;
1186 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1187 default: ret = "";
1188 }
1189 return ret;
1190}
1191
1192static void get_function_bounds(unsigned long pc, unsigned long *startp,
1193 unsigned long *endp)
1194{
1195 unsigned long size, offset;
1196 const char *name;
1197 char *modname;
1198
1199 *startp = *endp = 0;
1200 if (pc == 0)
1201 return;
1202 if (setjmp(bus_error_jmp) == 0) {
1203 catch_memory_errors = 1;
1204 sync();
1205 name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
1206 if (name != NULL) {
1207 *startp = pc - offset;
1208 *endp = pc - offset + size;
1209 }
1210 sync();
1211 }
1212 catch_memory_errors = 0;
1213}
1214
1215static int xmon_depth_to_print = 64;
1216
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001217#ifdef CONFIG_PPC64
1218#define LRSAVE_OFFSET 0x10
1219#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1220#define MARKER_OFFSET 0x60
1221#define REGS_OFFSET 0x70
1222#else
1223#define LRSAVE_OFFSET 4
1224#define REG_FRAME_MARKER 0x72656773
1225#define MARKER_OFFSET 8
1226#define REGS_OFFSET 16
1227#endif
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229static void xmon_show_stack(unsigned long sp, unsigned long lr,
1230 unsigned long pc)
1231{
1232 unsigned long ip;
1233 unsigned long newsp;
1234 unsigned long marker;
1235 int count = 0;
1236 struct pt_regs regs;
1237
1238 do {
1239 if (sp < PAGE_OFFSET) {
1240 if (sp != 0)
1241 printf("SP (%lx) is in userspace\n", sp);
1242 break;
1243 }
1244
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001245 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 || !mread(sp, &newsp, sizeof(unsigned long))) {
1247 printf("Couldn't read stack frame at %lx\n", sp);
1248 break;
1249 }
1250
1251 /*
1252 * For the first stack frame, try to work out if
1253 * LR and/or the saved LR value in the bottommost
1254 * stack frame are valid.
1255 */
1256 if ((pc | lr) != 0) {
1257 unsigned long fnstart, fnend;
1258 unsigned long nextip;
1259 int printip = 1;
1260
1261 get_function_bounds(pc, &fnstart, &fnend);
1262 nextip = 0;
1263 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001264 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 sizeof(unsigned long));
1266 if (lr == ip) {
1267 if (lr < PAGE_OFFSET
1268 || (fnstart <= lr && lr < fnend))
1269 printip = 0;
1270 } else if (lr == nextip) {
1271 printip = 0;
1272 } else if (lr >= PAGE_OFFSET
1273 && !(fnstart <= lr && lr < fnend)) {
1274 printf("[link register ] ");
1275 xmon_print_symbol(lr, " ", "\n");
1276 }
1277 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001278 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 xmon_print_symbol(ip, " ", " (unreliable)\n");
1280 }
1281 pc = lr = 0;
1282
1283 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001284 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 xmon_print_symbol(ip, " ", "\n");
1286 }
1287
1288 /* Look for "regshere" marker to see if this is
1289 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001290 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1291 && marker == REG_FRAME_MARKER) {
1292 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 != sizeof(regs)) {
1294 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001295 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 break;
1297 }
1298 printf("--- Exception: %lx %s at ", regs.trap,
1299 getvecname(TRAP(&regs)));
1300 pc = regs.nip;
1301 lr = regs.link;
1302 xmon_print_symbol(pc, " ", "\n");
1303 }
1304
1305 if (newsp == 0)
1306 break;
1307
1308 sp = newsp;
1309 } while (count++ < xmon_depth_to_print);
1310}
1311
1312static void backtrace(struct pt_regs *excp)
1313{
1314 unsigned long sp;
1315
1316 if (scanhex(&sp))
1317 xmon_show_stack(sp, 0, 0);
1318 else
1319 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1320 scannl();
1321}
1322
1323static void print_bug_trap(struct pt_regs *regs)
1324{
1325 struct bug_entry *bug;
1326 unsigned long addr;
1327
1328 if (regs->msr & MSR_PR)
1329 return; /* not in kernel */
1330 addr = regs->nip; /* address of trap instruction */
1331 if (addr < PAGE_OFFSET)
1332 return;
1333 bug = find_bug(regs->nip);
1334 if (bug == NULL)
1335 return;
1336 if (bug->line & BUG_WARNING_TRAP)
1337 return;
1338
1339 printf("kernel BUG in %s at %s:%d!\n",
1340 bug->function, bug->file, (unsigned int)bug->line);
1341}
1342
1343void excprint(struct pt_regs *fp)
1344{
1345 unsigned long trap;
1346
1347#ifdef CONFIG_SMP
1348 printf("cpu 0x%x: ", smp_processor_id());
1349#endif /* CONFIG_SMP */
1350
1351 trap = TRAP(fp);
1352 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1353 printf(" pc: ");
1354 xmon_print_symbol(fp->nip, ": ", "\n");
1355
1356 printf(" lr: ", fp->link);
1357 xmon_print_symbol(fp->link, ": ", "\n");
1358
1359 printf(" sp: %lx\n", fp->gpr[1]);
1360 printf(" msr: %lx\n", fp->msr);
1361
1362 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1363 printf(" dar: %lx\n", fp->dar);
1364 if (trap != 0x380)
1365 printf(" dsisr: %lx\n", fp->dsisr);
1366 }
1367
1368 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001369#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001371#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 if (current) {
1373 printf(" pid = %ld, comm = %s\n",
1374 current->pid, current->comm);
1375 }
1376
1377 if (trap == 0x700)
1378 print_bug_trap(fp);
1379}
1380
1381void prregs(struct pt_regs *fp)
1382{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001383 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 unsigned long base;
1385 struct pt_regs regs;
1386
1387 if (scanhex(&base)) {
1388 if (setjmp(bus_error_jmp) == 0) {
1389 catch_memory_errors = 1;
1390 sync();
1391 regs = *(struct pt_regs *)base;
1392 sync();
1393 __delay(200);
1394 } else {
1395 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001396 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 base);
1398 return;
1399 }
1400 catch_memory_errors = 0;
1401 fp = &regs;
1402 }
1403
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001404#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 if (FULL_REGS(fp)) {
1406 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001407 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1409 } else {
1410 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001411 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1413 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001414#else
1415 for (n = 0; n < 32; ++n) {
1416 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1417 (n & 3) == 3? "\n": " ");
1418 if (n == 12 && !FULL_REGS(fp)) {
1419 printf("\n");
1420 break;
1421 }
1422 }
1423#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 printf("pc = ");
1425 xmon_print_symbol(fp->nip, " ", "\n");
1426 printf("lr = ");
1427 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001428 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1429 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001431 trap = TRAP(fp);
1432 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1433 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434}
1435
1436void cacheflush(void)
1437{
1438 int cmd;
1439 unsigned long nflush;
1440
1441 cmd = inchar();
1442 if (cmd != 'i')
1443 termch = cmd;
1444 scanhex((void *)&adrs);
1445 if (termch != '\n')
1446 termch = 0;
1447 nflush = 1;
1448 scanhex(&nflush);
1449 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1450 if (setjmp(bus_error_jmp) == 0) {
1451 catch_memory_errors = 1;
1452 sync();
1453
1454 if (cmd != 'i') {
1455 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1456 cflush((void *) adrs);
1457 } else {
1458 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1459 cinval((void *) adrs);
1460 }
1461 sync();
1462 /* wait a little while to see if we get a machine check */
1463 __delay(200);
1464 }
1465 catch_memory_errors = 0;
1466}
1467
1468unsigned long
1469read_spr(int n)
1470{
1471 unsigned int instrs[2];
1472 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001474#ifdef CONFIG_PPC64
1475 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 opd[0] = (unsigned long)instrs;
1478 opd[1] = 0;
1479 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001480 code = (unsigned long (*)(void)) opd;
1481#else
1482 code = (unsigned long (*)(void)) instrs;
1483#endif
1484
1485 /* mfspr r3,n; blr */
1486 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1487 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 store_inst(instrs);
1489 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
1491 if (setjmp(bus_error_jmp) == 0) {
1492 catch_memory_errors = 1;
1493 sync();
1494
1495 ret = code();
1496
1497 sync();
1498 /* wait a little while to see if we get a machine check */
1499 __delay(200);
1500 n = size;
1501 }
1502
1503 return ret;
1504}
1505
1506void
1507write_spr(int n, unsigned long val)
1508{
1509 unsigned int instrs[2];
1510 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001511#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 unsigned long opd[3];
1513
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 opd[0] = (unsigned long)instrs;
1515 opd[1] = 0;
1516 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001517 code = (unsigned long (*)(unsigned long)) opd;
1518#else
1519 code = (unsigned long (*)(unsigned long)) instrs;
1520#endif
1521
1522 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1523 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 store_inst(instrs);
1525 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 if (setjmp(bus_error_jmp) == 0) {
1528 catch_memory_errors = 1;
1529 sync();
1530
1531 code(val);
1532
1533 sync();
1534 /* wait a little while to see if we get a machine check */
1535 __delay(200);
1536 n = size;
1537 }
1538}
1539
1540static unsigned long regno;
1541extern char exc_prolog;
1542extern char dec_exc;
1543
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001544void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
1546 int cmd;
1547 unsigned long val;
1548#ifdef CONFIG_PPC_ISERIES
1549 struct paca_struct *ptrPaca = NULL;
1550 struct lppaca *ptrLpPaca = NULL;
1551 struct ItLpRegSave *ptrLpRegSave = NULL;
1552#endif
1553
1554 cmd = skipbl();
1555 if (cmd == '\n') {
1556 unsigned long sp, toc;
1557 asm("mr %0,1" : "=r" (sp) :);
1558 asm("mr %0,2" : "=r" (toc) :);
1559
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001560 printf("msr = "REG" sprg0= "REG"\n",
1561 mfmsr(), mfspr(SPRN_SPRG0));
1562 printf("pvr = "REG" sprg1= "REG"\n",
1563 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1564 printf("dec = "REG" sprg2= "REG"\n",
1565 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1566 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1567 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568#ifdef CONFIG_PPC_ISERIES
1569 // Dump out relevant Paca data areas.
1570 printf("Paca: \n");
1571 ptrPaca = get_paca();
1572
1573 printf(" Local Processor Control Area (LpPaca): \n");
1574 ptrLpPaca = ptrPaca->lppaca_ptr;
1575 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1576 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1577 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1578 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1579 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1580
1581 printf(" Local Processor Register Save Area (LpRegSave): \n");
1582 ptrLpRegSave = ptrPaca->reg_save_ptr;
1583 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1584 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1585 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1586 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1587 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1588 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1589#endif
1590
1591 return;
1592 }
1593
1594 scanhex(&regno);
1595 switch (cmd) {
1596 case 'w':
1597 val = read_spr(regno);
1598 scanhex(&val);
1599 write_spr(regno, val);
1600 /* fall through */
1601 case 'r':
1602 printf("spr %lx = %lx\n", regno, read_spr(regno));
1603 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 }
1605 scannl();
1606}
1607
1608/*
1609 * Stuff for reading and writing memory safely
1610 */
1611int
1612mread(unsigned long adrs, void *buf, int size)
1613{
1614 volatile int n;
1615 char *p, *q;
1616
1617 n = 0;
1618 if (setjmp(bus_error_jmp) == 0) {
1619 catch_memory_errors = 1;
1620 sync();
1621 p = (char *)adrs;
1622 q = (char *)buf;
1623 switch (size) {
1624 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001625 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 break;
1627 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001628 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 break;
1630 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001631 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 break;
1633 default:
1634 for( ; n < size; ++n) {
1635 *q++ = *p++;
1636 sync();
1637 }
1638 }
1639 sync();
1640 /* wait a little while to see if we get a machine check */
1641 __delay(200);
1642 n = size;
1643 }
1644 catch_memory_errors = 0;
1645 return n;
1646}
1647
1648int
1649mwrite(unsigned long adrs, void *buf, int size)
1650{
1651 volatile int n;
1652 char *p, *q;
1653
1654 n = 0;
1655 if (setjmp(bus_error_jmp) == 0) {
1656 catch_memory_errors = 1;
1657 sync();
1658 p = (char *) adrs;
1659 q = (char *) buf;
1660 switch (size) {
1661 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001662 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 break;
1664 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001665 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 break;
1667 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001668 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 break;
1670 default:
1671 for ( ; n < size; ++n) {
1672 *p++ = *q++;
1673 sync();
1674 }
1675 }
1676 sync();
1677 /* wait a little while to see if we get a machine check */
1678 __delay(200);
1679 n = size;
1680 } else {
1681 printf("*** Error writing address %x\n", adrs + n);
1682 }
1683 catch_memory_errors = 0;
1684 return n;
1685}
1686
1687static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001688static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689static char *fault_chars[] = { "--", "**", "##" };
1690
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001691static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001693 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 switch (TRAP(regs)) {
1695 case 0x200:
1696 fault_type = 0;
1697 break;
1698 case 0x300:
1699 case 0x380:
1700 fault_type = 1;
1701 break;
1702 default:
1703 fault_type = 2;
1704 }
1705
1706 longjmp(bus_error_jmp, 1);
1707
1708 return 0;
1709}
1710
1711#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1712
1713void
1714byterev(unsigned char *val, int size)
1715{
1716 int t;
1717
1718 switch (size) {
1719 case 2:
1720 SWAP(val[0], val[1], t);
1721 break;
1722 case 4:
1723 SWAP(val[0], val[3], t);
1724 SWAP(val[1], val[2], t);
1725 break;
1726 case 8: /* is there really any use for this? */
1727 SWAP(val[0], val[7], t);
1728 SWAP(val[1], val[6], t);
1729 SWAP(val[2], val[5], t);
1730 SWAP(val[3], val[4], t);
1731 break;
1732 }
1733}
1734
1735static int brev;
1736static int mnoread;
1737
1738static char *memex_help_string =
1739 "Memory examine command usage:\n"
1740 "m [addr] [flags] examine/change memory\n"
1741 " addr is optional. will start where left off.\n"
1742 " flags may include chars from this set:\n"
1743 " b modify by bytes (default)\n"
1744 " w modify by words (2 byte)\n"
1745 " l modify by longs (4 byte)\n"
1746 " d modify by doubleword (8 byte)\n"
1747 " r toggle reverse byte order mode\n"
1748 " n do not read memory (for i/o spaces)\n"
1749 " . ok to read (default)\n"
1750 "NOTE: flags are saved as defaults\n"
1751 "";
1752
1753static char *memex_subcmd_help_string =
1754 "Memory examine subcommands:\n"
1755 " hexval write this val to current location\n"
1756 " 'string' write chars from string to this location\n"
1757 " ' increment address\n"
1758 " ^ decrement address\n"
1759 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1760 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1761 " ` clear no-read flag\n"
1762 " ; stay at this addr\n"
1763 " v change to byte mode\n"
1764 " w change to word (2 byte) mode\n"
1765 " l change to long (4 byte) mode\n"
1766 " u change to doubleword (8 byte) mode\n"
1767 " m addr change current addr\n"
1768 " n toggle no-read flag\n"
1769 " r toggle byte reverse flag\n"
1770 " < count back up count bytes\n"
1771 " > count skip forward count bytes\n"
1772 " x exit this mode\n"
1773 "";
1774
1775void
1776memex(void)
1777{
1778 int cmd, inc, i, nslash;
1779 unsigned long n;
1780 unsigned char val[16];
1781
1782 scanhex((void *)&adrs);
1783 cmd = skipbl();
1784 if (cmd == '?') {
1785 printf(memex_help_string);
1786 return;
1787 } else {
1788 termch = cmd;
1789 }
1790 last_cmd = "m\n";
1791 while ((cmd = skipbl()) != '\n') {
1792 switch( cmd ){
1793 case 'b': size = 1; break;
1794 case 'w': size = 2; break;
1795 case 'l': size = 4; break;
1796 case 'd': size = 8; break;
1797 case 'r': brev = !brev; break;
1798 case 'n': mnoread = 1; break;
1799 case '.': mnoread = 0; break;
1800 }
1801 }
1802 if( size <= 0 )
1803 size = 1;
1804 else if( size > 8 )
1805 size = 8;
1806 for(;;){
1807 if (!mnoread)
1808 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001809 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 if (!mnoread) {
1811 if (brev)
1812 byterev(val, size);
1813 putchar(' ');
1814 for (i = 0; i < n; ++i)
1815 printf("%.2x", val[i]);
1816 for (; i < size; ++i)
1817 printf("%s", fault_chars[fault_type]);
1818 }
1819 putchar(' ');
1820 inc = size;
1821 nslash = 0;
1822 for(;;){
1823 if( scanhex(&n) ){
1824 for (i = 0; i < size; ++i)
1825 val[i] = n >> (i * 8);
1826 if (!brev)
1827 byterev(val, size);
1828 mwrite(adrs, val, size);
1829 inc = size;
1830 }
1831 cmd = skipbl();
1832 if (cmd == '\n')
1833 break;
1834 inc = 0;
1835 switch (cmd) {
1836 case '\'':
1837 for(;;){
1838 n = inchar();
1839 if( n == '\\' )
1840 n = bsesc();
1841 else if( n == '\'' )
1842 break;
1843 for (i = 0; i < size; ++i)
1844 val[i] = n >> (i * 8);
1845 if (!brev)
1846 byterev(val, size);
1847 mwrite(adrs, val, size);
1848 adrs += size;
1849 }
1850 adrs -= size;
1851 inc = size;
1852 break;
1853 case ',':
1854 adrs += size;
1855 break;
1856 case '.':
1857 mnoread = 0;
1858 break;
1859 case ';':
1860 break;
1861 case 'x':
1862 case EOF:
1863 scannl();
1864 return;
1865 case 'b':
1866 case 'v':
1867 size = 1;
1868 break;
1869 case 'w':
1870 size = 2;
1871 break;
1872 case 'l':
1873 size = 4;
1874 break;
1875 case 'u':
1876 size = 8;
1877 break;
1878 case '^':
1879 adrs -= size;
1880 break;
1881 break;
1882 case '/':
1883 if (nslash > 0)
1884 adrs -= 1 << nslash;
1885 else
1886 nslash = 0;
1887 nslash += 4;
1888 adrs += 1 << nslash;
1889 break;
1890 case '\\':
1891 if (nslash < 0)
1892 adrs += 1 << -nslash;
1893 else
1894 nslash = 0;
1895 nslash -= 4;
1896 adrs -= 1 << -nslash;
1897 break;
1898 case 'm':
1899 scanhex((void *)&adrs);
1900 break;
1901 case 'n':
1902 mnoread = 1;
1903 break;
1904 case 'r':
1905 brev = !brev;
1906 break;
1907 case '<':
1908 n = size;
1909 scanhex(&n);
1910 adrs -= n;
1911 break;
1912 case '>':
1913 n = size;
1914 scanhex(&n);
1915 adrs += n;
1916 break;
1917 case '?':
1918 printf(memex_subcmd_help_string);
1919 break;
1920 }
1921 }
1922 adrs += inc;
1923 }
1924}
1925
1926int
1927bsesc(void)
1928{
1929 int c;
1930
1931 c = inchar();
1932 switch( c ){
1933 case 'n': c = '\n'; break;
1934 case 'r': c = '\r'; break;
1935 case 'b': c = '\b'; break;
1936 case 't': c = '\t'; break;
1937 }
1938 return c;
1939}
1940
1941#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
1942 || ('a' <= (c) && (c) <= 'f') \
1943 || ('A' <= (c) && (c) <= 'F'))
1944void
1945dump(void)
1946{
1947 int c;
1948
1949 c = inchar();
1950 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1951 termch = c;
1952 scanhex((void *)&adrs);
1953 if (termch != '\n')
1954 termch = 0;
1955 if (c == 'i') {
1956 scanhex(&nidump);
1957 if (nidump == 0)
1958 nidump = 16;
1959 else if (nidump > MAX_DUMP)
1960 nidump = MAX_DUMP;
1961 adrs += ppc_inst_dump(adrs, nidump, 1);
1962 last_cmd = "di\n";
1963 } else {
1964 scanhex(&ndump);
1965 if (ndump == 0)
1966 ndump = 64;
1967 else if (ndump > MAX_DUMP)
1968 ndump = MAX_DUMP;
1969 prdump(adrs, ndump);
1970 adrs += ndump;
1971 last_cmd = "d\n";
1972 }
1973}
1974
1975void
1976prdump(unsigned long adrs, long ndump)
1977{
1978 long n, m, c, r, nr;
1979 unsigned char temp[16];
1980
1981 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001982 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 putchar(' ');
1984 r = n < 16? n: 16;
1985 nr = mread(adrs, temp, r);
1986 adrs += nr;
1987 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001988 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
1989 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 if (m < nr)
1991 printf("%.2x", temp[m]);
1992 else
1993 printf("%s", fault_chars[fault_type]);
1994 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001995 for (; m < 16; ++m) {
1996 if ((m & (sizeof(long) - 1)) == 0)
1997 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 printf(" |");
2001 for (m = 0; m < r; ++m) {
2002 if (m < nr) {
2003 c = temp[m];
2004 putchar(' ' <= c && c <= '~'? c: '.');
2005 } else
2006 putchar(' ');
2007 }
2008 n -= r;
2009 for (; m < 16; ++m)
2010 putchar(' ');
2011 printf("|\n");
2012 if (nr < r)
2013 break;
2014 }
2015}
2016
2017int
2018ppc_inst_dump(unsigned long adr, long count, int praddr)
2019{
2020 int nr, dotted;
2021 unsigned long first_adr;
2022 unsigned long inst, last_inst = 0;
2023 unsigned char val[4];
2024
2025 dotted = 0;
2026 for (first_adr = adr; count > 0; --count, adr += 4) {
2027 nr = mread(adr, val, 4);
2028 if (nr == 0) {
2029 if (praddr) {
2030 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002031 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 }
2033 break;
2034 }
2035 inst = GETWORD(val);
2036 if (adr > first_adr && inst == last_inst) {
2037 if (!dotted) {
2038 printf(" ...\n");
2039 dotted = 1;
2040 }
2041 continue;
2042 }
2043 dotted = 0;
2044 last_inst = inst;
2045 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002046 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 printf("\t");
2048 print_insn_powerpc(inst, adr, 0); /* always returns 4 */
2049 printf("\n");
2050 }
2051 return adr - first_adr;
2052}
2053
2054void
2055print_address(unsigned long addr)
2056{
2057 xmon_print_symbol(addr, "\t# ", "");
2058}
2059
2060
2061/*
2062 * Memory operations - move, set, print differences
2063 */
2064static unsigned long mdest; /* destination address */
2065static unsigned long msrc; /* source address */
2066static unsigned long mval; /* byte value to set memory to */
2067static unsigned long mcount; /* # bytes to affect */
2068static unsigned long mdiffs; /* max # differences to print */
2069
2070void
2071memops(int cmd)
2072{
2073 scanhex((void *)&mdest);
2074 if( termch != '\n' )
2075 termch = 0;
2076 scanhex((void *)(cmd == 's'? &mval: &msrc));
2077 if( termch != '\n' )
2078 termch = 0;
2079 scanhex((void *)&mcount);
2080 switch( cmd ){
2081 case 'm':
2082 memmove((void *)mdest, (void *)msrc, mcount);
2083 break;
2084 case 's':
2085 memset((void *)mdest, mval, mcount);
2086 break;
2087 case 'd':
2088 if( termch != '\n' )
2089 termch = 0;
2090 scanhex((void *)&mdiffs);
2091 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2092 break;
2093 }
2094}
2095
2096void
2097memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2098{
2099 unsigned n, prt;
2100
2101 prt = 0;
2102 for( n = nb; n > 0; --n )
2103 if( *p1++ != *p2++ )
2104 if( ++prt <= maxpr )
2105 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2106 p1[-1], p2 - 1, p2[-1]);
2107 if( prt > maxpr )
2108 printf("Total of %d differences\n", prt);
2109}
2110
2111static unsigned mend;
2112static unsigned mask;
2113
2114void
2115memlocate(void)
2116{
2117 unsigned a, n;
2118 unsigned char val[4];
2119
2120 last_cmd = "ml";
2121 scanhex((void *)&mdest);
2122 if (termch != '\n') {
2123 termch = 0;
2124 scanhex((void *)&mend);
2125 if (termch != '\n') {
2126 termch = 0;
2127 scanhex((void *)&mval);
2128 mask = ~0;
2129 if (termch != '\n') termch = 0;
2130 scanhex((void *)&mask);
2131 }
2132 }
2133 n = 0;
2134 for (a = mdest; a < mend; a += 4) {
2135 if (mread(a, val, 4) == 4
2136 && ((GETWORD(val) ^ mval) & mask) == 0) {
2137 printf("%.16x: %.16x\n", a, GETWORD(val));
2138 if (++n >= 10)
2139 break;
2140 }
2141 }
2142}
2143
2144static unsigned long mskip = 0x1000;
2145static unsigned long mlim = 0xffffffff;
2146
2147void
2148memzcan(void)
2149{
2150 unsigned char v;
2151 unsigned a;
2152 int ok, ook;
2153
2154 scanhex(&mdest);
2155 if (termch != '\n') termch = 0;
2156 scanhex(&mskip);
2157 if (termch != '\n') termch = 0;
2158 scanhex(&mlim);
2159 ook = 0;
2160 for (a = mdest; a < mlim; a += mskip) {
2161 ok = mread(a, &v, 1);
2162 if (ok && !ook) {
2163 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 } else if (!ok && ook)
2165 printf("%.8x\n", a - mskip);
2166 ook = ok;
2167 if (a + mskip < a)
2168 break;
2169 }
2170 if (ook)
2171 printf("%.8x\n", a - mskip);
2172}
2173
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002174void proccall(void)
2175{
2176 unsigned long args[8];
2177 unsigned long ret;
2178 int i;
2179 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2180 unsigned long, unsigned long, unsigned long,
2181 unsigned long, unsigned long, unsigned long);
2182 callfunc_t func;
2183
2184 if (!scanhex(&adrs))
2185 return;
2186 if (termch != '\n')
2187 termch = 0;
2188 for (i = 0; i < 8; ++i)
2189 args[i] = 0;
2190 for (i = 0; i < 8; ++i) {
2191 if (!scanhex(&args[i]) || termch == '\n')
2192 break;
2193 termch = 0;
2194 }
2195 func = (callfunc_t) adrs;
2196 ret = 0;
2197 if (setjmp(bus_error_jmp) == 0) {
2198 catch_memory_errors = 1;
2199 sync();
2200 ret = func(args[0], args[1], args[2], args[3],
2201 args[4], args[5], args[6], args[7]);
2202 sync();
2203 printf("return value is %x\n", ret);
2204 } else {
2205 printf("*** %x exception occurred\n", fault_except);
2206 }
2207 catch_memory_errors = 0;
2208}
2209
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210/* Input scanning routines */
2211int
2212skipbl(void)
2213{
2214 int c;
2215
2216 if( termch != 0 ){
2217 c = termch;
2218 termch = 0;
2219 } else
2220 c = inchar();
2221 while( c == ' ' || c == '\t' )
2222 c = inchar();
2223 return c;
2224}
2225
2226#define N_PTREGS 44
2227static char *regnames[N_PTREGS] = {
2228 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2229 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2230 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2231 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002232 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2233#ifdef CONFIG_PPC64
2234 "softe",
2235#else
2236 "mq",
2237#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 "trap", "dar", "dsisr", "res"
2239};
2240
2241int
2242scanhex(unsigned long *vp)
2243{
2244 int c, d;
2245 unsigned long v;
2246
2247 c = skipbl();
2248 if (c == '%') {
2249 /* parse register name */
2250 char regname[8];
2251 int i;
2252
2253 for (i = 0; i < sizeof(regname) - 1; ++i) {
2254 c = inchar();
2255 if (!isalnum(c)) {
2256 termch = c;
2257 break;
2258 }
2259 regname[i] = c;
2260 }
2261 regname[i] = 0;
2262 for (i = 0; i < N_PTREGS; ++i) {
2263 if (strcmp(regnames[i], regname) == 0) {
2264 if (xmon_regs == NULL) {
2265 printf("regs not available\n");
2266 return 0;
2267 }
2268 *vp = ((unsigned long *)xmon_regs)[i];
2269 return 1;
2270 }
2271 }
2272 printf("invalid register name '%%%s'\n", regname);
2273 return 0;
2274 }
2275
2276 /* skip leading "0x" if any */
2277
2278 if (c == '0') {
2279 c = inchar();
2280 if (c == 'x') {
2281 c = inchar();
2282 } else {
2283 d = hexdigit(c);
2284 if (d == EOF) {
2285 termch = c;
2286 *vp = 0;
2287 return 1;
2288 }
2289 }
2290 } else if (c == '$') {
2291 int i;
2292 for (i=0; i<63; i++) {
2293 c = inchar();
2294 if (isspace(c)) {
2295 termch = c;
2296 break;
2297 }
2298 tmpstr[i] = c;
2299 }
2300 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002301 *vp = 0;
2302 if (setjmp(bus_error_jmp) == 0) {
2303 catch_memory_errors = 1;
2304 sync();
2305 *vp = kallsyms_lookup_name(tmpstr);
2306 sync();
2307 }
2308 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 if (!(*vp)) {
2310 printf("unknown symbol '%s'\n", tmpstr);
2311 return 0;
2312 }
2313 return 1;
2314 }
2315
2316 d = hexdigit(c);
2317 if (d == EOF) {
2318 termch = c;
2319 return 0;
2320 }
2321 v = 0;
2322 do {
2323 v = (v << 4) + d;
2324 c = inchar();
2325 d = hexdigit(c);
2326 } while (d != EOF);
2327 termch = c;
2328 *vp = v;
2329 return 1;
2330}
2331
2332void
2333scannl(void)
2334{
2335 int c;
2336
2337 c = termch;
2338 termch = 0;
2339 while( c != '\n' )
2340 c = inchar();
2341}
2342
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002343int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344{
2345 if( '0' <= c && c <= '9' )
2346 return c - '0';
2347 if( 'A' <= c && c <= 'F' )
2348 return c - ('A' - 10);
2349 if( 'a' <= c && c <= 'f' )
2350 return c - ('a' - 10);
2351 return EOF;
2352}
2353
2354void
2355getstring(char *s, int size)
2356{
2357 int c;
2358
2359 c = skipbl();
2360 do {
2361 if( size > 1 ){
2362 *s++ = c;
2363 --size;
2364 }
2365 c = inchar();
2366 } while( c != ' ' && c != '\t' && c != '\n' );
2367 termch = c;
2368 *s = 0;
2369}
2370
2371static char line[256];
2372static char *lineptr;
2373
2374void
2375flush_input(void)
2376{
2377 lineptr = NULL;
2378}
2379
2380int
2381inchar(void)
2382{
2383 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002384 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 lineptr = NULL;
2386 return EOF;
2387 }
2388 lineptr = line;
2389 }
2390 return *lineptr++;
2391}
2392
2393void
2394take_input(char *str)
2395{
2396 lineptr = str;
2397}
2398
2399
2400static void
2401symbol_lookup(void)
2402{
2403 int type = inchar();
2404 unsigned long addr;
2405 static char tmp[64];
2406
2407 switch (type) {
2408 case 'a':
2409 if (scanhex(&addr))
2410 xmon_print_symbol(addr, ": ", "\n");
2411 termch = 0;
2412 break;
2413 case 's':
2414 getstring(tmp, 64);
2415 if (setjmp(bus_error_jmp) == 0) {
2416 catch_memory_errors = 1;
2417 sync();
2418 addr = kallsyms_lookup_name(tmp);
2419 if (addr)
2420 printf("%s: %lx\n", tmp, addr);
2421 else
2422 printf("Symbol '%s' not found.\n", tmp);
2423 sync();
2424 }
2425 catch_memory_errors = 0;
2426 termch = 0;
2427 break;
2428 }
2429}
2430
2431
2432/* Print an address in numeric and symbolic form (if possible) */
2433static void xmon_print_symbol(unsigned long address, const char *mid,
2434 const char *after)
2435{
2436 char *modname;
2437 const char *name = NULL;
2438 unsigned long offset, size;
2439
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002440 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 if (setjmp(bus_error_jmp) == 0) {
2442 catch_memory_errors = 1;
2443 sync();
2444 name = kallsyms_lookup(address, &size, &offset, &modname,
2445 tmpstr);
2446 sync();
2447 /* wait a little while to see if we get a machine check */
2448 __delay(200);
2449 }
2450
2451 catch_memory_errors = 0;
2452
2453 if (name) {
2454 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2455 if (modname)
2456 printf(" [%s]", modname);
2457 }
2458 printf("%s", after);
2459}
2460
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002461#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462static void dump_slb(void)
2463{
2464 int i;
2465 unsigned long tmp;
2466
2467 printf("SLB contents of cpu %x\n", smp_processor_id());
2468
2469 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2470 asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
2471 printf("%02d %016lx ", i, tmp);
2472
2473 asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
2474 printf("%016lx\n", tmp);
2475 }
2476}
2477
2478static void dump_stab(void)
2479{
2480 int i;
2481 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2482
2483 printf("Segment table contents of cpu %x\n", smp_processor_id());
2484
2485 for (i = 0; i < PAGE_SIZE/16; i++) {
2486 unsigned long a, b;
2487
2488 a = *tmp++;
2489 b = *tmp++;
2490
2491 if (a || b) {
2492 printf("%03d %016lx ", i, a);
2493 printf("%016lx\n", b);
2494 }
2495 }
2496}
2497
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002498void dump_segments(void)
2499{
2500 if (cpu_has_feature(CPU_FTR_SLB))
2501 dump_slb();
2502 else
2503 dump_stab();
2504}
2505#endif
2506
2507#ifdef CONFIG_PPC_STD_MMU_32
2508void dump_segments(void)
2509{
2510 int i;
2511
2512 printf("sr0-15 =");
2513 for (i = 0; i < 16; ++i)
2514 printf(" %x", mfsrin(i));
2515 printf("\n");
2516}
2517#endif
2518
Olaf Heringb13cfd172005-08-04 19:26:42 +02002519void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002521 if (enable) {
2522 __debugger = xmon;
2523 __debugger_ipi = xmon_ipi;
2524 __debugger_bpt = xmon_bpt;
2525 __debugger_sstep = xmon_sstep;
2526 __debugger_iabr_match = xmon_iabr_match;
2527 __debugger_dabr_match = xmon_dabr_match;
2528 __debugger_fault_handler = xmon_fault_handler;
2529 } else {
2530 __debugger = NULL;
2531 __debugger_ipi = NULL;
2532 __debugger_bpt = NULL;
2533 __debugger_sstep = NULL;
2534 __debugger_iabr_match = NULL;
2535 __debugger_dabr_match = NULL;
2536 __debugger_fault_handler = NULL;
2537 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002538 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002540
2541#ifdef CONFIG_MAGIC_SYSRQ
2542static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
2543 struct tty_struct *tty)
2544{
2545 /* ensure xmon is enabled */
2546 xmon_init(1);
2547 debugger(pt_regs);
2548}
2549
2550static struct sysrq_key_op sysrq_xmon_op =
2551{
2552 .handler = sysrq_handle_xmon,
2553 .help_msg = "Xmon",
2554 .action_msg = "Entering xmon",
2555};
2556
2557static int __init setup_xmon_sysrq(void)
2558{
2559 register_sysrq_key('x', &sysrq_xmon_op);
2560 return 0;
2561}
2562__initcall(setup_xmon_sysrq);
2563#endif /* CONFIG_MAGIC_SYSRQ */