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