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