blob: b1a91744fd2db09086d79af4846e74d3c9ba518a [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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <linux/errno.h>
7#include <linux/sched.h>
8#include <linux/smp.h>
9#include <linux/interrupt.h>
10#include <linux/bitops.h>
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -070011#include <linux/kallsyms.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <asm/ptrace.h>
13#include <asm/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <asm/machdep.h>
15#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "nonstdio.h"
17#include "privinst.h"
18
19#define scanhex xmon_scanhex
20#define skipbl xmon_skipbl
21
22#ifdef CONFIG_SMP
23static unsigned long cpus_in_xmon = 0;
24static unsigned long got_xmon = 0;
25static volatile int take_xmon = -1;
26#endif /* CONFIG_SMP */
27
28static unsigned adrs;
29static int size = 1;
30static unsigned ndump = 64;
31static unsigned nidump = 16;
32static unsigned ncsum = 4096;
33static int termch;
34
35static u_int bus_error_jmp[100];
36#define setjmp xmon_setjmp
37#define longjmp xmon_longjmp
38
39/* Breakpoint stuff */
40struct bpt {
41 unsigned address;
42 unsigned instr;
43 unsigned count;
44 unsigned char enabled;
45};
46
47#define NBPTS 16
48static struct bpt bpts[NBPTS];
49static struct bpt dabr;
50static struct bpt iabr;
51static unsigned bpinstr = 0x7fe00008; /* trap */
52
53/* Prototypes */
54extern void (*debugger_fault_handler)(struct pt_regs *);
55static int cmds(struct pt_regs *);
56static int mread(unsigned, void *, int);
57static int mwrite(unsigned, void *, int);
58static void handle_fault(struct pt_regs *);
59static void byterev(unsigned char *, int);
60static void memex(void);
61static int bsesc(void);
62static void dump(void);
63static void prdump(unsigned, int);
64#ifdef __MWERKS__
65static void prndump(unsigned, int);
66static int nvreadb(unsigned);
67#endif
68static int ppc_inst_dump(unsigned, int);
69void print_address(unsigned);
70static int getsp(void);
71static void dump_hash_table(void);
72static void backtrace(struct pt_regs *);
73static void excprint(struct pt_regs *);
74static void prregs(struct pt_regs *);
75static void memops(int);
76static void memlocate(void);
77static void memzcan(void);
78static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
79int skipbl(void);
80int scanhex(unsigned *valp);
81static void scannl(void);
82static int hexdigit(int);
83void getstring(char *, int);
84static void flush_input(void);
85static int inchar(void);
86static void take_input(char *);
87/* static void openforth(void); */
88static unsigned read_spr(int);
89static void write_spr(int, unsigned);
90static void super_regs(void);
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -070091static void symbol_lookup(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static void remove_bpts(void);
93static void insert_bpts(void);
94static struct bpt *at_breakpoint(unsigned pc);
95static void bpt_cmds(void);
akpm@osdl.org198e2f12006-01-12 01:05:30 -080096void cacheflush(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097#ifdef CONFIG_SMP
98static void cpu_cmd(void);
99#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100static void csum(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static void bootcmds(void);
102static void proccall(void);
103static void printtime(void);
104
105extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
106extern void printf(const char *fmt, ...);
107extern int putchar(int ch);
108extern int setjmp(u_int *);
109extern void longjmp(u_int *, int);
110
111extern void xmon_enter(void);
112extern void xmon_leave(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114static unsigned start_tb[NR_CPUS][2];
115static unsigned stop_tb[NR_CPUS][2];
116
117#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
118
119#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
120 || ('a' <= (c) && (c) <= 'f') \
121 || ('A' <= (c) && (c) <= 'F'))
122#define isalnum(c) (('0' <= (c) && (c) <= '9') \
123 || ('a' <= (c) && (c) <= 'z') \
124 || ('A' <= (c) && (c) <= 'Z'))
125#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
126
127static char *help_string = "\
128Commands:\n\
129 d dump bytes\n\
130 di dump instructions\n\
131 df dump float values\n\
132 dd dump double values\n\
133 e print exception information\n\
134 h dump hash table\n\
135 m examine/change memory\n\
136 mm move a block of memory\n\
137 ms set a block of memory\n\
138 md compare two blocks of memory\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 r print registers\n\
140 S print special registers\n\
141 t print backtrace\n\
Olaf Heringd49b3402005-10-28 17:46:17 -0700142 la lookup address\n\
143 ls lookup symbol\n\
144 C checksum\n\
145 p call function with arguments\n\
146 T print time\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 x exit monitor\n\
Olaf Heringd49b3402005-10-28 17:46:17 -0700148 zr reboot\n\
149 zh halt\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150";
151
152static int xmon_trace[NR_CPUS];
153#define SSTEP 1 /* stepping because of 's' command */
154#define BRSTEP 2 /* stepping over breakpoint */
155
Josh Boyerb7e89212006-09-07 13:27:58 -0500156#ifdef CONFIG_4xx
157#define MSR_SSTEP_ENABLE 0x200
158#else
159#define MSR_SSTEP_ENABLE 0x400
160#endif
161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static struct pt_regs *xmon_regs[NR_CPUS];
163
164extern inline void sync(void)
165{
166 asm volatile("sync; isync");
167}
168
169extern inline void __delay(unsigned int loops)
170{
171 if (loops != 0)
172 __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
173 "r" (loops) : "ctr");
174}
175
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700176/* Print an address in numeric and symbolic form (if possible) */
177static void xmon_print_symbol(unsigned long address, const char *mid,
178 const char *after)
179{
180 char *modname;
181 const char *name = NULL;
182 unsigned long offset, size;
183 static char tmpstr[128];
184
185 printf("%.8lx", address);
186 if (setjmp(bus_error_jmp) == 0) {
187 debugger_fault_handler = handle_fault;
188 sync();
189 name = kallsyms_lookup(address, &size, &offset, &modname,
190 tmpstr);
191 sync();
192 /* wait a little while to see if we get a machine check */
193 __delay(200);
194 }
195 debugger_fault_handler = NULL;
196
197 if (name) {
198 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
199 if (modname)
200 printf(" [%s]", modname);
201 }
202 printf("%s", after);
203}
204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205static void get_tb(unsigned *p)
206{
207 unsigned hi, lo, hiagain;
208
209 if ((get_pvr() >> 16) == 1)
210 return;
211
212 do {
213 asm volatile("mftbu %0; mftb %1; mftbu %2"
214 : "=r" (hi), "=r" (lo), "=r" (hiagain));
215 } while (hi != hiagain);
216 p[0] = hi;
217 p[1] = lo;
218}
219
Josh Boyerb7e89212006-09-07 13:27:58 -0500220static inline void xmon_enable_sstep(struct pt_regs *regs)
221{
222 regs->msr |= MSR_SSTEP_ENABLE;
223#ifdef CONFIG_4xx
224 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
225#endif
226}
227
Benjamin Herrenschmidt7b007de2005-11-07 16:43:44 +1100228int xmon(struct pt_regs *excp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 struct pt_regs regs;
231 int msr, cmd;
232
233 get_tb(stop_tb[smp_processor_id()]);
234 if (excp == NULL) {
235 asm volatile ("stw 0,0(%0)\n\
236 lwz 0,0(1)\n\
237 stw 0,4(%0)\n\
238 stmw 2,8(%0)" : : "b" (&regs));
239 regs.nip = regs.link = ((unsigned long *)regs.gpr[1])[1];
240 regs.msr = get_msr();
241 regs.ctr = get_ctr();
242 regs.xer = get_xer();
243 regs.ccr = get_cr();
244 regs.trap = 0;
245 excp = &regs;
246 }
247
248 msr = get_msr();
249 set_msr(msr & ~0x8000); /* disable interrupts */
250 xmon_regs[smp_processor_id()] = excp;
251 xmon_enter();
252 excprint(excp);
253#ifdef CONFIG_SMP
254 if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
255 for (;;)
256 ;
257 while (test_and_set_bit(0, &got_xmon)) {
258 if (take_xmon == smp_processor_id()) {
259 take_xmon = -1;
260 break;
261 }
262 }
263 /*
264 * XXX: breakpoints are removed while any cpu is in xmon
265 */
266#endif /* CONFIG_SMP */
267 remove_bpts();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 cmd = cmds(excp);
269 if (cmd == 's') {
270 xmon_trace[smp_processor_id()] = SSTEP;
Josh Boyerb7e89212006-09-07 13:27:58 -0500271 xmon_enable_sstep(excp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 } else if (at_breakpoint(excp->nip)) {
273 xmon_trace[smp_processor_id()] = BRSTEP;
Josh Boyerb7e89212006-09-07 13:27:58 -0500274 xmon_enable_sstep(excp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 } else {
276 xmon_trace[smp_processor_id()] = 0;
277 insert_bpts();
278 }
279 xmon_leave();
280 xmon_regs[smp_processor_id()] = NULL;
281#ifdef CONFIG_SMP
282 clear_bit(0, &got_xmon);
283 clear_bit(smp_processor_id(), &cpus_in_xmon);
284#endif /* CONFIG_SMP */
285 set_msr(msr); /* restore interrupt enable */
286 get_tb(start_tb[smp_processor_id()]);
Benjamin Herrenschmidt7b007de2005-11-07 16:43:44 +1100287
288 return cmd != 'X';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289}
290
291irqreturn_t
292xmon_irq(int irq, void *d, struct pt_regs *regs)
293{
294 unsigned long flags;
295 local_irq_save(flags);
296 printf("Keyboard interrupt\n");
297 xmon(regs);
298 local_irq_restore(flags);
299 return IRQ_HANDLED;
300}
301
302int
303xmon_bpt(struct pt_regs *regs)
304{
305 struct bpt *bp;
306
307 bp = at_breakpoint(regs->nip);
308 if (!bp)
309 return 0;
310 if (bp->count) {
311 --bp->count;
312 remove_bpts();
313 excprint(regs);
314 xmon_trace[smp_processor_id()] = BRSTEP;
Josh Boyerb7e89212006-09-07 13:27:58 -0500315 xmon_enable_sstep(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 } else {
317 xmon(regs);
318 }
319 return 1;
320}
321
322int
323xmon_sstep(struct pt_regs *regs)
324{
325 if (!xmon_trace[smp_processor_id()])
326 return 0;
327 if (xmon_trace[smp_processor_id()] == BRSTEP) {
328 xmon_trace[smp_processor_id()] = 0;
329 insert_bpts();
330 } else {
331 xmon(regs);
332 }
333 return 1;
334}
335
336int
337xmon_dabr_match(struct pt_regs *regs)
338{
339 if (dabr.enabled && dabr.count) {
340 --dabr.count;
341 remove_bpts();
342 excprint(regs);
343 xmon_trace[smp_processor_id()] = BRSTEP;
344 regs->msr |= 0x400;
345 } else {
346 dabr.instr = regs->nip;
347 xmon(regs);
348 }
349 return 1;
350}
351
352int
353xmon_iabr_match(struct pt_regs *regs)
354{
355 if (iabr.enabled && iabr.count) {
356 --iabr.count;
357 remove_bpts();
358 excprint(regs);
359 xmon_trace[smp_processor_id()] = BRSTEP;
360 regs->msr |= 0x400;
361 } else {
362 xmon(regs);
363 }
364 return 1;
365}
366
367static struct bpt *
368at_breakpoint(unsigned pc)
369{
370 int i;
371 struct bpt *bp;
372
373 if (dabr.enabled && pc == dabr.instr)
374 return &dabr;
375 if (iabr.enabled && pc == iabr.address)
376 return &iabr;
377 bp = bpts;
378 for (i = 0; i < NBPTS; ++i, ++bp)
379 if (bp->enabled && pc == bp->address)
380 return bp;
381 return NULL;
382}
383
384static void
385insert_bpts(void)
386{
387 int i;
388 struct bpt *bp;
389
390 bp = bpts;
391 for (i = 0; i < NBPTS; ++i, ++bp) {
392 if (!bp->enabled)
393 continue;
394 if (mread(bp->address, &bp->instr, 4) != 4
395 || mwrite(bp->address, &bpinstr, 4) != 4) {
396 printf("Couldn't insert breakpoint at %x, disabling\n",
397 bp->address);
398 bp->enabled = 0;
399 }
400 store_inst((void *) bp->address);
401 }
Josh Boyerb7e89212006-09-07 13:27:58 -0500402#if ! (defined(CONFIG_8xx) || defined(CONFIG_4xx))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 if (dabr.enabled)
404 set_dabr(dabr.address);
405 if (iabr.enabled)
406 set_iabr(iabr.address);
407#endif
408}
409
410static void
411remove_bpts(void)
412{
413 int i;
414 struct bpt *bp;
415 unsigned instr;
416
Josh Boyerb7e89212006-09-07 13:27:58 -0500417#if ! (defined(CONFIG_8xx) || defined(CONFIG_4xx))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 set_dabr(0);
419 set_iabr(0);
420#endif
421 bp = bpts;
422 for (i = 0; i < NBPTS; ++i, ++bp) {
423 if (!bp->enabled)
424 continue;
425 if (mread(bp->address, &instr, 4) == 4
426 && instr == bpinstr
427 && mwrite(bp->address, &bp->instr, 4) != 4)
428 printf("Couldn't remove breakpoint at %x\n",
429 bp->address);
430 store_inst((void *) bp->address);
431 }
432}
433
434static char *last_cmd;
435
436/* Command interpreting routine */
437static int
438cmds(struct pt_regs *excp)
439{
440 int cmd;
441
442 last_cmd = NULL;
443 for(;;) {
444#ifdef CONFIG_SMP
445 printf("%d:", smp_processor_id());
446#endif /* CONFIG_SMP */
447 printf("mon> ");
448 fflush(stdout);
449 flush_input();
450 termch = 0;
451 cmd = skipbl();
452 if( cmd == '\n' ) {
453 if (last_cmd == NULL)
454 continue;
455 take_input(last_cmd);
456 last_cmd = NULL;
457 cmd = inchar();
458 }
459 switch (cmd) {
460 case 'm':
461 cmd = inchar();
462 switch (cmd) {
463 case 'm':
464 case 's':
465 case 'd':
466 memops(cmd);
467 break;
468 case 'l':
469 memlocate();
470 break;
471 case 'z':
472 memzcan();
473 break;
474 default:
475 termch = cmd;
476 memex();
477 }
478 break;
479 case 'd':
480 dump();
481 break;
482 case 'l':
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700483 symbol_lookup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 break;
485 case 'r':
486 if (excp != NULL)
487 prregs(excp); /* print regs */
488 break;
489 case 'e':
490 if (excp == NULL)
491 printf("No exception information\n");
492 else
493 excprint(excp);
494 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 case 'S':
496 super_regs();
497 break;
498 case 't':
499 backtrace(excp);
500 break;
501 case 'f':
502 cacheflush();
503 break;
504 case 'h':
505 dump_hash_table();
506 break;
507 case 's':
508 case 'x':
509 case EOF:
510 return cmd;
511 case '?':
512 printf(help_string);
513 break;
514 default:
515 printf("Unrecognized command: ");
516 if( ' ' < cmd && cmd <= '~' )
517 putchar(cmd);
518 else
519 printf("\\x%x", cmd);
520 printf(" (type ? for help)\n");
521 break;
522 case 'b':
523 bpt_cmds();
524 break;
525 case 'C':
526 csum();
527 break;
528#ifdef CONFIG_SMP
529 case 'c':
530 cpu_cmd();
531 break;
532#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 case 'z':
534 bootcmds();
535 break;
536 case 'p':
537 proccall();
538 break;
539 case 'T':
540 printtime();
541 break;
542 }
543 }
544}
545
546extern unsigned tb_to_us;
547
548#define mulhwu(x,y) \
549({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
550
551static void printtime(void)
552{
553 unsigned int delta;
554
555 delta = stop_tb[smp_processor_id()][1]
556 - start_tb[smp_processor_id()][1];
557 delta = mulhwu(tb_to_us, delta);
558 printf("%u.%06u seconds\n", delta / 1000000, delta % 1000000);
559}
560
561static void bootcmds(void)
562{
563 int cmd;
564
565 cmd = inchar();
566 if (cmd == 'r')
567 ppc_md.restart(NULL);
568 else if (cmd == 'h')
569 ppc_md.halt();
570 else if (cmd == 'p')
571 ppc_md.power_off();
572}
573
574#ifdef CONFIG_SMP
575static void cpu_cmd(void)
576{
577 unsigned cpu;
578 int timeout;
579 int cmd;
580
581 cmd = inchar();
582 if (cmd == 'i') {
583 /* interrupt other cpu(s) */
584 cpu = MSG_ALL_BUT_SELF;
585 if (scanhex(&cpu))
586 smp_send_xmon_break(cpu);
587 return;
588 }
589 termch = cmd;
590 if (!scanhex(&cpu)) {
591 /* print cpus waiting or in xmon */
592 printf("cpus stopped:");
593 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
594 if (test_bit(cpu, &cpus_in_xmon)) {
595 printf(" %d", cpu);
596 if (cpu == smp_processor_id())
597 printf("*", cpu);
598 }
599 }
600 printf("\n");
601 return;
602 }
603 /* try to switch to cpu specified */
604 take_xmon = cpu;
605 timeout = 10000000;
606 while (take_xmon >= 0) {
607 if (--timeout == 0) {
608 /* yes there's a race here */
609 take_xmon = -1;
610 printf("cpu %u didn't take control\n", cpu);
611 return;
612 }
613 }
614 /* now have to wait to be given control back */
615 while (test_and_set_bit(0, &got_xmon)) {
616 if (take_xmon == smp_processor_id()) {
617 take_xmon = -1;
618 break;
619 }
620 }
621}
622#endif /* CONFIG_SMP */
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625static unsigned short fcstab[256] = {
626 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
627 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
628 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
629 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
630 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
631 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
632 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
633 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
634 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
635 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
636 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
637 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
638 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
639 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
640 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
641 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
642 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
643 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
644 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
645 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
646 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
647 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
648 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
649 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
650 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
651 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
652 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
653 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
654 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
655 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
656 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
657 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
658};
659
660#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
661
662static void
663csum(void)
664{
665 unsigned int i;
666 unsigned short fcs;
667 unsigned char v;
668
669 if (!scanhex(&adrs))
670 return;
671 if (!scanhex(&ncsum))
672 return;
673 fcs = 0xffff;
674 for (i = 0; i < ncsum; ++i) {
675 if (mread(adrs+i, &v, 1) == 0) {
676 printf("csum stopped at %x\n", adrs+i);
677 break;
678 }
679 fcs = FCS(fcs, v);
680 }
681 printf("%x\n", fcs);
682}
683
684static void
685bpt_cmds(void)
686{
687 int cmd;
688 unsigned a;
689 int mode, i;
690 struct bpt *bp;
691
692 cmd = inchar();
693 switch (cmd) {
Josh Boyerb7e89212006-09-07 13:27:58 -0500694#if ! (defined(CONFIG_8xx) || defined(CONFIG_4xx))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 case 'd':
696 mode = 7;
697 cmd = inchar();
698 if (cmd == 'r')
699 mode = 5;
700 else if (cmd == 'w')
701 mode = 6;
702 else
703 termch = cmd;
704 cmd = inchar();
705 if (cmd == 'p')
706 mode &= ~4;
707 else
708 termch = cmd;
709 dabr.address = 0;
710 dabr.count = 0;
711 dabr.enabled = scanhex(&dabr.address);
712 scanhex(&dabr.count);
713 if (dabr.enabled)
714 dabr.address = (dabr.address & ~7) | mode;
715 break;
716 case 'i':
717 cmd = inchar();
718 if (cmd == 'p')
719 mode = 2;
720 else
721 mode = 3;
722 iabr.address = 0;
723 iabr.count = 0;
724 iabr.enabled = scanhex(&iabr.address);
725 if (iabr.enabled)
726 iabr.address |= mode;
727 scanhex(&iabr.count);
728 break;
729#endif
730 case 'c':
731 if (!scanhex(&a)) {
732 /* clear all breakpoints */
733 for (i = 0; i < NBPTS; ++i)
734 bpts[i].enabled = 0;
735 iabr.enabled = 0;
736 dabr.enabled = 0;
737 printf("All breakpoints cleared\n");
738 } else {
739 bp = at_breakpoint(a);
740 if (bp == 0) {
741 printf("No breakpoint at %x\n", a);
742 } else {
743 bp->enabled = 0;
744 }
745 }
746 break;
747 default:
748 termch = cmd;
749 if (!scanhex(&a)) {
750 /* print all breakpoints */
751 printf("type address count\n");
752 if (dabr.enabled) {
753 printf("data %.8x %8x [", dabr.address & ~7,
754 dabr.count);
755 if (dabr.address & 1)
756 printf("r");
757 if (dabr.address & 2)
758 printf("w");
759 if (!(dabr.address & 4))
760 printf("p");
761 printf("]\n");
762 }
763 if (iabr.enabled)
764 printf("inst %.8x %8x\n", iabr.address & ~3,
765 iabr.count);
766 for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
767 if (bp->enabled)
768 printf("trap %.8x %8x\n", bp->address,
769 bp->count);
770 break;
771 }
772 bp = at_breakpoint(a);
773 if (bp == 0) {
774 for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
775 if (!bp->enabled)
776 break;
777 if (bp >= &bpts[NBPTS]) {
778 printf("Sorry, no free breakpoints\n");
779 break;
780 }
781 }
782 bp->enabled = 1;
783 bp->address = a;
784 bp->count = 0;
785 scanhex(&bp->count);
786 break;
787 }
788}
789
790static void
791backtrace(struct pt_regs *excp)
792{
793 unsigned sp;
794 unsigned stack[2];
795 struct pt_regs regs;
796 extern char ret_from_except, ret_from_except_full, ret_from_syscall;
797
798 printf("backtrace:\n");
799
800 if (excp != NULL)
801 sp = excp->gpr[1];
802 else
803 sp = getsp();
804 scanhex(&sp);
805 scannl();
806 for (; sp != 0; sp = stack[0]) {
807 if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
808 break;
Josh Boyer4dbefe62006-09-15 14:53:10 -0500809 printf("[%.8lx] ", stack[0]);
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700810 xmon_print_symbol(stack[1], " ", "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (stack[1] == (unsigned) &ret_from_except
812 || stack[1] == (unsigned) &ret_from_except_full
813 || stack[1] == (unsigned) &ret_from_syscall) {
814 if (mread(sp+16, &regs, sizeof(regs)) != sizeof(regs))
815 break;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700816 printf("exception:%x [%x] %x\n", regs.trap, sp+16,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 regs.nip);
818 sp = regs.gpr[1];
819 if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
820 break;
821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
823}
824
825int
826getsp(void)
827{
828 int x;
829
830 asm("mr %0,1" : "=r" (x) :);
831 return x;
832}
833
834void
835excprint(struct pt_regs *fp)
836{
837 int trap;
838
839#ifdef CONFIG_SMP
840 printf("cpu %d: ", smp_processor_id());
841#endif /* CONFIG_SMP */
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700842 printf("vector: %x at pc=", fp->trap);
843 xmon_print_symbol(fp->nip, ": ", ", lr=");
844 xmon_print_symbol(fp->link, ": ", "\n");
845 printf("msr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 trap = TRAP(fp);
847 if (trap == 0x300 || trap == 0x600)
848 printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
849 if (current)
850 printf("current = %x, pid = %d, comm = %s\n",
851 current, current->pid, current->comm);
852}
853
854void
855prregs(struct pt_regs *fp)
856{
857 int n;
858 unsigned base;
859
860 if (scanhex(&base))
861 fp = (struct pt_regs *) base;
862 for (n = 0; n < 32; ++n) {
863 printf("R%.2d = %.8x%s", n, fp->gpr[n],
864 (n & 3) == 3? "\n": " ");
865 if (n == 12 && !FULL_REGS(fp)) {
866 printf("\n");
867 break;
868 }
869 }
870 printf("pc = %.8x msr = %.8x lr = %.8x cr = %.8x\n",
871 fp->nip, fp->msr, fp->link, fp->ccr);
872 printf("ctr = %.8x xer = %.8x trap = %4x\n",
873 fp->ctr, fp->xer, fp->trap);
874}
875
876void
877cacheflush(void)
878{
879 int cmd;
880 unsigned nflush;
881
882 cmd = inchar();
883 if (cmd != 'i')
884 termch = cmd;
885 scanhex(&adrs);
886 if (termch != '\n')
887 termch = 0;
888 nflush = 1;
889 scanhex(&nflush);
890 nflush = (nflush + 31) / 32;
891 if (cmd != 'i') {
892 for (; nflush > 0; --nflush, adrs += 0x20)
893 cflush((void *) adrs);
894 } else {
895 for (; nflush > 0; --nflush, adrs += 0x20)
896 cinval((void *) adrs);
897 }
898}
899
900unsigned int
901read_spr(int n)
902{
903 unsigned int instrs[2];
904 int (*code)(void);
905
906 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
907 instrs[1] = 0x4e800020;
908 store_inst(instrs);
909 store_inst(instrs+1);
910 code = (int (*)(void)) instrs;
911 return code();
912}
913
914void
915write_spr(int n, unsigned int val)
916{
917 unsigned int instrs[2];
918 int (*code)(unsigned int);
919
920 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
921 instrs[1] = 0x4e800020;
922 store_inst(instrs);
923 store_inst(instrs+1);
924 code = (int (*)(unsigned int)) instrs;
925 code(val);
926}
927
928static unsigned int regno;
929extern char exc_prolog;
930extern char dec_exc;
931
932void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933super_regs(void)
934{
935 int i, cmd;
936 unsigned val;
937
938 cmd = skipbl();
939 if (cmd == '\n') {
940 printf("msr = %x, pvr = %x\n", get_msr(), get_pvr());
941 printf("sprg0-3 = %x %x %x %x\n", get_sprg0(), get_sprg1(),
942 get_sprg2(), get_sprg3());
943 printf("srr0 = %x, srr1 = %x\n", get_srr0(), get_srr1());
944#ifdef CONFIG_PPC_STD_MMU
945 printf("sr0-15 =");
946 for (i = 0; i < 16; ++i)
947 printf(" %x", get_sr(i));
948 printf("\n");
949#endif
950 asm("mr %0,1" : "=r" (i) :);
951 printf("sp = %x ", i);
952 asm("mr %0,2" : "=r" (i) :);
953 printf("toc = %x\n", i);
954 return;
955 }
956
957 scanhex(&regno);
958 switch (cmd) {
959 case 'w':
960 val = read_spr(regno);
961 scanhex(&val);
962 write_spr(regno, val);
963 /* fall through */
964 case 'r':
965 printf("spr %x = %x\n", regno, read_spr(regno));
966 break;
967 case 's':
968 val = get_sr(regno);
969 scanhex(&val);
970 set_sr(regno, val);
971 break;
972 case 'm':
973 val = get_msr();
974 scanhex(&val);
975 set_msr(val);
976 break;
977 }
978 scannl();
979}
980
981#ifndef CONFIG_PPC_STD_MMU
982static void
983dump_hash_table(void)
984{
985 printf("This CPU doesn't have a hash table.\n");
986}
987#else
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989static void
990dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
991{
992 extern void *Hash;
993 extern unsigned long Hash_size;
994 unsigned *htab = Hash;
995 unsigned hsize = Hash_size;
996 unsigned v, hmask, va, last_va = 0;
997 int found, last_found, i;
998 unsigned *hg, w1, last_w2 = 0, last_va0 = 0;
999
1000 last_found = 0;
1001 hmask = hsize / 64 - 1;
1002 va = start;
1003 start = (start >> 12) & 0xffff;
1004 end = (end >> 12) & 0xffff;
1005 for (v = start; v < end; ++v) {
1006 found = 0;
1007 hg = htab + (((v ^ seg) & hmask) * 16);
1008 w1 = 0x80000000 | (seg << 7) | (v >> 10);
1009 for (i = 0; i < 8; ++i, hg += 2) {
1010 if (*hg == w1) {
1011 found = 1;
1012 break;
1013 }
1014 }
1015 if (!found) {
1016 w1 ^= 0x40;
1017 hg = htab + ((~(v ^ seg) & hmask) * 16);
1018 for (i = 0; i < 8; ++i, hg += 2) {
1019 if (*hg == w1) {
1020 found = 1;
1021 break;
1022 }
1023 }
1024 }
1025 if (!(last_found && found && (hg[1] & ~0x180) == last_w2 + 4096)) {
1026 if (last_found) {
1027 if (last_va != last_va0)
1028 printf(" ... %x", last_va);
1029 printf("\n");
1030 }
1031 if (found) {
1032 printf("%x to %x", va, hg[1]);
1033 last_va0 = va;
1034 }
1035 last_found = found;
1036 }
1037 if (found) {
1038 last_w2 = hg[1] & ~0x180;
1039 last_va = va;
1040 }
1041 va += 4096;
1042 }
1043 if (last_found)
1044 printf(" ... %x\n", last_va);
1045}
1046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047static unsigned hash_ctx;
1048static unsigned hash_start;
1049static unsigned hash_end;
1050
1051static void
1052dump_hash_table(void)
1053{
1054 int seg;
1055 unsigned seg_start, seg_end;
1056
1057 hash_ctx = 0;
1058 hash_start = 0;
1059 hash_end = 0xfffff000;
1060 scanhex(&hash_ctx);
1061 scanhex(&hash_start);
1062 scanhex(&hash_end);
1063 printf("Mappings for context %x\n", hash_ctx);
1064 seg_start = hash_start;
1065 for (seg = hash_start >> 28; seg <= hash_end >> 28; ++seg) {
1066 seg_end = (seg << 28) | 0x0ffff000;
1067 if (seg_end > hash_end)
1068 seg_end = hash_end;
1069 dump_hash_table_seg((hash_ctx << 4) + (seg * 0x111),
1070 seg_start, seg_end);
1071 seg_start = seg_end + 0x1000;
1072 }
1073}
1074#endif /* CONFIG_PPC_STD_MMU */
1075
1076/*
1077 * Stuff for reading and writing memory safely
1078 */
1079
1080int
1081mread(unsigned adrs, void *buf, int size)
1082{
1083 volatile int n;
1084 char *p, *q;
1085
1086 n = 0;
1087 if( setjmp(bus_error_jmp) == 0 ){
1088 debugger_fault_handler = handle_fault;
1089 sync();
1090 p = (char *) adrs;
1091 q = (char *) buf;
1092 switch (size) {
1093 case 2: *(short *)q = *(short *)p; break;
1094 case 4: *(int *)q = *(int *)p; break;
1095 default:
1096 for( ; n < size; ++n ) {
1097 *q++ = *p++;
1098 sync();
1099 }
1100 }
1101 sync();
1102 /* wait a little while to see if we get a machine check */
1103 __delay(200);
1104 n = size;
1105 }
1106 debugger_fault_handler = NULL;
1107 return n;
1108}
1109
1110int
1111mwrite(unsigned adrs, void *buf, int size)
1112{
1113 volatile int n;
1114 char *p, *q;
1115
1116 n = 0;
1117 if( setjmp(bus_error_jmp) == 0 ){
1118 debugger_fault_handler = handle_fault;
1119 sync();
1120 p = (char *) adrs;
1121 q = (char *) buf;
1122 switch (size) {
1123 case 2: *(short *)p = *(short *)q; break;
1124 case 4: *(int *)p = *(int *)q; break;
1125 default:
1126 for( ; n < size; ++n ) {
1127 *p++ = *q++;
1128 sync();
1129 }
1130 }
1131 sync();
1132 n = size;
1133 } else {
1134 printf("*** Error writing address %x\n", adrs + n);
1135 }
1136 debugger_fault_handler = NULL;
1137 return n;
1138}
1139
1140static int fault_type;
1141static int fault_except;
1142static char *fault_chars[] = { "--", "**", "##" };
1143
1144static void
1145handle_fault(struct pt_regs *regs)
1146{
1147 fault_except = TRAP(regs);
1148 fault_type = TRAP(regs) == 0x200? 0: TRAP(regs) == 0x300? 1: 2;
1149 longjmp(bus_error_jmp, 1);
1150}
1151
1152#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1153
1154void
1155byterev(unsigned char *val, int size)
1156{
1157 int t;
1158
1159 switch (size) {
1160 case 2:
1161 SWAP(val[0], val[1], t);
1162 break;
1163 case 4:
1164 SWAP(val[0], val[3], t);
1165 SWAP(val[1], val[2], t);
1166 break;
1167 }
1168}
1169
1170static int brev;
1171static int mnoread;
1172
1173void
1174memex(void)
1175{
1176 int cmd, inc, i, nslash;
1177 unsigned n;
1178 unsigned char val[4];
1179
1180 last_cmd = "m\n";
1181 scanhex(&adrs);
1182 while ((cmd = skipbl()) != '\n') {
1183 switch( cmd ){
1184 case 'b': size = 1; break;
1185 case 'w': size = 2; break;
1186 case 'l': size = 4; break;
1187 case 'r': brev = !brev; break;
1188 case 'n': mnoread = 1; break;
1189 case '.': mnoread = 0; break;
1190 }
1191 }
1192 if( size <= 0 )
1193 size = 1;
1194 else if( size > 4 )
1195 size = 4;
1196 for(;;){
1197 if (!mnoread)
1198 n = mread(adrs, val, size);
1199 printf("%.8x%c", adrs, brev? 'r': ' ');
1200 if (!mnoread) {
1201 if (brev)
1202 byterev(val, size);
1203 putchar(' ');
1204 for (i = 0; i < n; ++i)
1205 printf("%.2x", val[i]);
1206 for (; i < size; ++i)
1207 printf("%s", fault_chars[fault_type]);
1208 }
1209 putchar(' ');
1210 inc = size;
1211 nslash = 0;
1212 for(;;){
1213 if( scanhex(&n) ){
1214 for (i = 0; i < size; ++i)
1215 val[i] = n >> (i * 8);
1216 if (!brev)
1217 byterev(val, size);
1218 mwrite(adrs, val, size);
1219 inc = size;
1220 }
1221 cmd = skipbl();
1222 if (cmd == '\n')
1223 break;
1224 inc = 0;
1225 switch (cmd) {
1226 case '\'':
1227 for(;;){
1228 n = inchar();
1229 if( n == '\\' )
1230 n = bsesc();
1231 else if( n == '\'' )
1232 break;
1233 for (i = 0; i < size; ++i)
1234 val[i] = n >> (i * 8);
1235 if (!brev)
1236 byterev(val, size);
1237 mwrite(adrs, val, size);
1238 adrs += size;
1239 }
1240 adrs -= size;
1241 inc = size;
1242 break;
1243 case ',':
1244 adrs += size;
1245 break;
1246 case '.':
1247 mnoread = 0;
1248 break;
1249 case ';':
1250 break;
1251 case 'x':
1252 case EOF:
1253 scannl();
1254 return;
1255 case 'b':
1256 case 'v':
1257 size = 1;
1258 break;
1259 case 'w':
1260 size = 2;
1261 break;
1262 case 'l':
1263 size = 4;
1264 break;
1265 case '^':
1266 adrs -= size;
1267 break;
1268 break;
1269 case '/':
1270 if (nslash > 0)
1271 adrs -= 1 << nslash;
1272 else
1273 nslash = 0;
1274 nslash += 4;
1275 adrs += 1 << nslash;
1276 break;
1277 case '\\':
1278 if (nslash < 0)
1279 adrs += 1 << -nslash;
1280 else
1281 nslash = 0;
1282 nslash -= 4;
1283 adrs -= 1 << -nslash;
1284 break;
1285 case 'm':
1286 scanhex(&adrs);
1287 break;
1288 case 'n':
1289 mnoread = 1;
1290 break;
1291 case 'r':
1292 brev = !brev;
1293 break;
1294 case '<':
1295 n = size;
1296 scanhex(&n);
1297 adrs -= n;
1298 break;
1299 case '>':
1300 n = size;
1301 scanhex(&n);
1302 adrs += n;
1303 break;
1304 }
1305 }
1306 adrs += inc;
1307 }
1308}
1309
1310int
1311bsesc(void)
1312{
1313 int c;
1314
1315 c = inchar();
1316 switch( c ){
1317 case 'n': c = '\n'; break;
1318 case 'r': c = '\r'; break;
1319 case 'b': c = '\b'; break;
1320 case 't': c = '\t'; break;
1321 }
1322 return c;
1323}
1324
1325void
1326dump(void)
1327{
1328 int c;
1329
1330 c = inchar();
1331 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1332 termch = c;
1333 scanhex(&adrs);
1334 if( termch != '\n')
1335 termch = 0;
1336 if( c == 'i' ){
1337 scanhex(&nidump);
1338 if( nidump == 0 )
1339 nidump = 16;
1340 adrs += ppc_inst_dump(adrs, nidump);
1341 last_cmd = "di\n";
1342 } else {
1343 scanhex(&ndump);
1344 if( ndump == 0 )
1345 ndump = 64;
1346 prdump(adrs, ndump);
1347 adrs += ndump;
1348 last_cmd = "d\n";
1349 }
1350}
1351
1352void
1353prdump(unsigned adrs, int ndump)
1354{
1355 register int n, m, c, r, nr;
1356 unsigned char temp[16];
1357
1358 for( n = ndump; n > 0; ){
1359 printf("%.8x", adrs);
1360 putchar(' ');
1361 r = n < 16? n: 16;
1362 nr = mread(adrs, temp, r);
1363 adrs += nr;
1364 for( m = 0; m < r; ++m ){
1365 putchar((m & 3) == 0 && m > 0? '.': ' ');
1366 if( m < nr )
1367 printf("%.2x", temp[m]);
1368 else
1369 printf("%s", fault_chars[fault_type]);
1370 }
1371 for(; m < 16; ++m )
1372 printf(" ");
1373 printf(" |");
1374 for( m = 0; m < r; ++m ){
1375 if( m < nr ){
1376 c = temp[m];
1377 putchar(' ' <= c && c <= '~'? c: '.');
1378 } else
1379 putchar(' ');
1380 }
1381 n -= r;
1382 for(; m < 16; ++m )
1383 putchar(' ');
1384 printf("|\n");
1385 if( nr < r )
1386 break;
1387 }
1388}
1389
1390int
1391ppc_inst_dump(unsigned adr, int count)
1392{
1393 int nr, dotted;
1394 unsigned first_adr;
1395 unsigned long inst, last_inst = 0;
1396 unsigned char val[4];
1397
1398 dotted = 0;
1399 for (first_adr = adr; count > 0; --count, adr += 4){
1400 nr = mread(adr, val, 4);
1401 if( nr == 0 ){
1402 const char *x = fault_chars[fault_type];
1403 printf("%.8x %s%s%s%s\n", adr, x, x, x, x);
1404 break;
1405 }
1406 inst = GETWORD(val);
1407 if (adr > first_adr && inst == last_inst) {
1408 if (!dotted) {
1409 printf(" ...\n");
1410 dotted = 1;
1411 }
1412 continue;
1413 }
1414 dotted = 0;
1415 last_inst = inst;
1416 printf("%.8x ", adr);
1417 printf("%.8x\t", inst);
1418 print_insn_big_powerpc(stdout, inst, adr); /* always returns 4 */
1419 printf("\n");
1420 }
1421 return adr - first_adr;
1422}
1423
1424void
1425print_address(unsigned addr)
1426{
1427 printf("0x%x", addr);
1428}
1429
1430/*
1431 * Memory operations - move, set, print differences
1432 */
1433static unsigned mdest; /* destination address */
1434static unsigned msrc; /* source address */
1435static unsigned mval; /* byte value to set memory to */
1436static unsigned mcount; /* # bytes to affect */
1437static unsigned mdiffs; /* max # differences to print */
1438
1439void
1440memops(int cmd)
1441{
1442 scanhex(&mdest);
1443 if( termch != '\n' )
1444 termch = 0;
1445 scanhex(cmd == 's'? &mval: &msrc);
1446 if( termch != '\n' )
1447 termch = 0;
1448 scanhex(&mcount);
1449 switch( cmd ){
1450 case 'm':
1451 memmove((void *)mdest, (void *)msrc, mcount);
1452 break;
1453 case 's':
1454 memset((void *)mdest, mval, mcount);
1455 break;
1456 case 'd':
1457 if( termch != '\n' )
1458 termch = 0;
1459 scanhex(&mdiffs);
1460 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
1461 break;
1462 }
1463}
1464
1465void
1466memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
1467{
1468 unsigned n, prt;
1469
1470 prt = 0;
1471 for( n = nb; n > 0; --n )
1472 if( *p1++ != *p2++ )
1473 if( ++prt <= maxpr )
1474 printf("%.8x %.2x # %.8x %.2x\n", (unsigned)p1 - 1,
1475 p1[-1], (unsigned)p2 - 1, p2[-1]);
1476 if( prt > maxpr )
1477 printf("Total of %d differences\n", prt);
1478}
1479
1480static unsigned mend;
1481static unsigned mask;
1482
1483void
1484memlocate(void)
1485{
1486 unsigned a, n;
1487 unsigned char val[4];
1488
1489 last_cmd = "ml";
1490 scanhex(&mdest);
1491 if (termch != '\n') {
1492 termch = 0;
1493 scanhex(&mend);
1494 if (termch != '\n') {
1495 termch = 0;
1496 scanhex(&mval);
1497 mask = ~0;
1498 if (termch != '\n') termch = 0;
1499 scanhex(&mask);
1500 }
1501 }
1502 n = 0;
1503 for (a = mdest; a < mend; a += 4) {
1504 if (mread(a, val, 4) == 4
1505 && ((GETWORD(val) ^ mval) & mask) == 0) {
1506 printf("%.8x: %.8x\n", a, GETWORD(val));
1507 if (++n >= 10)
1508 break;
1509 }
1510 }
1511}
1512
1513static unsigned mskip = 0x1000;
1514static unsigned mlim = 0xffffffff;
1515
1516void
1517memzcan(void)
1518{
1519 unsigned char v;
1520 unsigned a;
1521 int ok, ook;
1522
1523 scanhex(&mdest);
1524 if (termch != '\n') termch = 0;
1525 scanhex(&mskip);
1526 if (termch != '\n') termch = 0;
1527 scanhex(&mlim);
1528 ook = 0;
1529 for (a = mdest; a < mlim; a += mskip) {
1530 ok = mread(a, &v, 1);
1531 if (ok && !ook) {
1532 printf("%.8x .. ", a);
1533 fflush(stdout);
1534 } else if (!ok && ook)
1535 printf("%.8x\n", a - mskip);
1536 ook = ok;
1537 if (a + mskip < a)
1538 break;
1539 }
1540 if (ook)
1541 printf("%.8x\n", a - mskip);
1542}
1543
1544void proccall(void)
1545{
1546 unsigned int args[8];
1547 unsigned int ret;
1548 int i;
1549 typedef unsigned int (*callfunc_t)(unsigned int, unsigned int,
1550 unsigned int, unsigned int, unsigned int,
1551 unsigned int, unsigned int, unsigned int);
1552 callfunc_t func;
1553
1554 scanhex(&adrs);
1555 if (termch != '\n')
1556 termch = 0;
1557 for (i = 0; i < 8; ++i)
1558 args[i] = 0;
1559 for (i = 0; i < 8; ++i) {
1560 if (!scanhex(&args[i]) || termch == '\n')
1561 break;
1562 termch = 0;
1563 }
1564 func = (callfunc_t) adrs;
1565 ret = 0;
1566 if (setjmp(bus_error_jmp) == 0) {
1567 debugger_fault_handler = handle_fault;
1568 sync();
1569 ret = func(args[0], args[1], args[2], args[3],
1570 args[4], args[5], args[6], args[7]);
1571 sync();
1572 printf("return value is %x\n", ret);
1573 } else {
1574 printf("*** %x exception occurred\n", fault_except);
1575 }
1576 debugger_fault_handler = NULL;
1577}
1578
1579/* Input scanning routines */
1580int
1581skipbl(void)
1582{
1583 int c;
1584
1585 if( termch != 0 ){
1586 c = termch;
1587 termch = 0;
1588 } else
1589 c = inchar();
1590 while( c == ' ' || c == '\t' )
1591 c = inchar();
1592 return c;
1593}
1594
1595#define N_PTREGS 44
1596static char *regnames[N_PTREGS] = {
1597 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1598 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
1599 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
1600 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
1601 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq",
1602 "trap", "dar", "dsisr", "res"
1603};
1604
1605int
1606scanhex(unsigned *vp)
1607{
1608 int c, d;
1609 unsigned v;
1610
1611 c = skipbl();
1612 if (c == '%') {
1613 /* parse register name */
1614 char regname[8];
1615 int i;
1616
1617 for (i = 0; i < sizeof(regname) - 1; ++i) {
1618 c = inchar();
1619 if (!isalnum(c)) {
1620 termch = c;
1621 break;
1622 }
1623 regname[i] = c;
1624 }
1625 regname[i] = 0;
1626 for (i = 0; i < N_PTREGS; ++i) {
1627 if (strcmp(regnames[i], regname) == 0) {
1628 unsigned *rp = (unsigned *)
1629 xmon_regs[smp_processor_id()];
1630 if (rp == NULL) {
1631 printf("regs not available\n");
1632 return 0;
1633 }
1634 *vp = rp[i];
1635 return 1;
1636 }
1637 }
1638 printf("invalid register name '%%%s'\n", regname);
1639 return 0;
1640 } else if (c == '$') {
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001641 static char symname[128];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 int i;
1643 for (i=0; i<63; i++) {
1644 c = inchar();
1645 if (isspace(c)) {
1646 termch = c;
1647 break;
1648 }
1649 symname[i] = c;
1650 }
1651 symname[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001652 *vp = 0;
1653 if (setjmp(bus_error_jmp) == 0) {
1654 debugger_fault_handler = handle_fault;
1655 sync();
1656 *vp = kallsyms_lookup_name(symname);
1657 sync();
1658 }
1659 debugger_fault_handler = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 if (!(*vp)) {
1661 printf("unknown symbol\n");
1662 return 0;
1663 }
1664 return 1;
1665 }
1666
1667 d = hexdigit(c);
1668 if( d == EOF ){
1669 termch = c;
1670 return 0;
1671 }
1672 v = 0;
1673 do {
1674 v = (v << 4) + d;
1675 c = inchar();
1676 d = hexdigit(c);
1677 } while( d != EOF );
1678 termch = c;
1679 *vp = v;
1680 return 1;
1681}
1682
1683void
1684scannl(void)
1685{
1686 int c;
1687
1688 c = termch;
1689 termch = 0;
1690 while( c != '\n' )
1691 c = inchar();
1692}
1693
1694int hexdigit(int c)
1695{
1696 if( '0' <= c && c <= '9' )
1697 return c - '0';
1698 if( 'A' <= c && c <= 'F' )
1699 return c - ('A' - 10);
1700 if( 'a' <= c && c <= 'f' )
1701 return c - ('a' - 10);
1702 return EOF;
1703}
1704
1705void
1706getstring(char *s, int size)
1707{
1708 int c;
1709
1710 c = skipbl();
1711 do {
1712 if( size > 1 ){
1713 *s++ = c;
1714 --size;
1715 }
1716 c = inchar();
1717 } while( c != ' ' && c != '\t' && c != '\n' );
1718 termch = c;
1719 *s = 0;
1720}
1721
1722static char line[256];
1723static char *lineptr;
1724
1725void
1726flush_input(void)
1727{
1728 lineptr = NULL;
1729}
1730
1731int
1732inchar(void)
1733{
1734 if (lineptr == NULL || *lineptr == 0) {
1735 if (fgets(line, sizeof(line), stdin) == NULL) {
1736 lineptr = NULL;
1737 return EOF;
1738 }
1739 lineptr = line;
1740 }
1741 return *lineptr++;
1742}
1743
1744void
1745take_input(char *str)
1746{
1747 lineptr = str;
1748}
1749
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001750static void
1751symbol_lookup(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752{
1753 int type = inchar();
1754 unsigned addr;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001755 static char tmp[128];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001757 switch (type) {
1758 case 'a':
1759 if (scanhex(&addr))
1760 xmon_print_symbol(addr, ": ", "\n");
1761 termch = 0;
1762 break;
1763 case 's':
1764 getstring(tmp, 64);
1765 if (setjmp(bus_error_jmp) == 0) {
1766 debugger_fault_handler = handle_fault;
1767 sync();
1768 addr = kallsyms_lookup_name(tmp);
1769 if (addr)
1770 printf("%s: %lx\n", tmp, addr);
1771 else
1772 printf("Symbol '%s' not found.\n", tmp);
1773 sync();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 }
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001775 debugger_fault_handler = NULL;
1776 termch = 0;
1777 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 }
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001779}
1780