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