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