xref: /OK3568_Linux_fs/u-boot/arch/powerpc/lib/kgdb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun #include <common.h>
2*4882a593Smuzhiyun #include <command.h>
3*4882a593Smuzhiyun #include <kgdb.h>
4*4882a593Smuzhiyun #include <asm/signal.h>
5*4882a593Smuzhiyun #include <asm/processor.h>
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #define PC_REGNUM 64
8*4882a593Smuzhiyun #define SP_REGNUM 1
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun void breakinst(void);
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun int
kgdb_setjmp(long * buf)13*4882a593Smuzhiyun kgdb_setjmp(long *buf)
14*4882a593Smuzhiyun {
15*4882a593Smuzhiyun 	unsigned long temp;
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun 	asm volatile("mflr %0; stw %0,0(%1);"
18*4882a593Smuzhiyun 	     "stw %%r1,4(%1); stw %%r2,8(%1);"
19*4882a593Smuzhiyun 	     "mfcr %0; stw %0,12(%1);"
20*4882a593Smuzhiyun 	     "stmw %%r13,16(%1)"
21*4882a593Smuzhiyun 	     : "=&r"(temp) : "r" (buf));
22*4882a593Smuzhiyun 	/* XXX should save fp regs as well */
23*4882a593Smuzhiyun 	return 0;
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun void
kgdb_longjmp(long * buf,int val)27*4882a593Smuzhiyun kgdb_longjmp(long *buf, int val)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	unsigned long temp;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	if (val == 0)
32*4882a593Smuzhiyun 		val = 1;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	asm volatile("lmw %%r13,16(%1);"
35*4882a593Smuzhiyun 	     "lwz %0,12(%1); mtcrf 0x38,%0;"
36*4882a593Smuzhiyun 	     "lwz %0,0(%1); lwz %%r1,4(%1); lwz %%r2,8(%1);"
37*4882a593Smuzhiyun 	     "mtlr %0; mr %%r3,%2"
38*4882a593Smuzhiyun 	     : "=&r"(temp) : "r" (buf), "r" (val));
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun /* Convert the SPARC hardware trap type code to a unix signal number. */
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun  * This table contains the mapping between PowerPC hardware trap types, and
44*4882a593Smuzhiyun  * signals, which are primarily what GDB understands.
45*4882a593Smuzhiyun  */
46*4882a593Smuzhiyun static struct hard_trap_info
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	unsigned int tt;		/* Trap type code for powerpc */
49*4882a593Smuzhiyun 	unsigned char signo;		/* Signal that we map this trap into */
50*4882a593Smuzhiyun } hard_trap_info[] = {
51*4882a593Smuzhiyun 	{ 0x200, SIGSEGV },			/* machine check */
52*4882a593Smuzhiyun 	{ 0x300, SIGSEGV },			/* address error (store) */
53*4882a593Smuzhiyun 	{ 0x400, SIGBUS },			/* instruction bus error */
54*4882a593Smuzhiyun 	{ 0x500, SIGINT },			/* interrupt */
55*4882a593Smuzhiyun 	{ 0x600, SIGBUS },			/* alingment */
56*4882a593Smuzhiyun 	{ 0x700, SIGTRAP },			/* breakpoint trap */
57*4882a593Smuzhiyun 	{ 0x800, SIGFPE },			/* fpu unavail */
58*4882a593Smuzhiyun 	{ 0x900, SIGALRM },			/* decrementer */
59*4882a593Smuzhiyun 	{ 0xa00, SIGILL },			/* reserved */
60*4882a593Smuzhiyun 	{ 0xb00, SIGILL },			/* reserved */
61*4882a593Smuzhiyun 	{ 0xc00, SIGCHLD },			/* syscall */
62*4882a593Smuzhiyun 	{ 0xd00, SIGTRAP },			/* single-step/watch */
63*4882a593Smuzhiyun 	{ 0xe00, SIGFPE },			/* fp assist */
64*4882a593Smuzhiyun 	{ 0, 0}				/* Must be last */
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun static int
computeSignal(unsigned int tt)68*4882a593Smuzhiyun computeSignal(unsigned int tt)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	struct hard_trap_info *ht;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
73*4882a593Smuzhiyun 		if (ht->tt == tt)
74*4882a593Smuzhiyun 			return ht->signo;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	return SIGHUP;         /* default for things we don't know about */
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun void
kgdb_enter(struct pt_regs * regs,kgdb_data * kdp)80*4882a593Smuzhiyun kgdb_enter(struct pt_regs *regs, kgdb_data *kdp)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	unsigned long msr;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	kdp->private[0] = msr = get_msr();
85*4882a593Smuzhiyun 	set_msr(msr & ~MSR_EE);	/* disable interrupts */
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (regs->nip == (unsigned long)breakinst) {
88*4882a593Smuzhiyun 		/* Skip over breakpoint trap insn */
89*4882a593Smuzhiyun 		regs->nip += 4;
90*4882a593Smuzhiyun 	}
91*4882a593Smuzhiyun 	regs->msr &= ~MSR_SE;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	/* reply to host that an exception has occurred */
94*4882a593Smuzhiyun 	kdp->sigval = computeSignal(regs->trap);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	kdp->nregs = 2;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	kdp->regs[0].num = PC_REGNUM;
99*4882a593Smuzhiyun 	kdp->regs[0].val = regs->nip;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	kdp->regs[1].num = SP_REGNUM;
102*4882a593Smuzhiyun 	kdp->regs[1].val = regs->gpr[SP_REGNUM];
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun void
kgdb_exit(struct pt_regs * regs,kgdb_data * kdp)106*4882a593Smuzhiyun kgdb_exit(struct pt_regs *regs, kgdb_data *kdp)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	unsigned long msr = kdp->private[0];
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	if (kdp->extype & KGDBEXIT_WITHADDR)
111*4882a593Smuzhiyun 		regs->nip = kdp->exaddr;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	switch (kdp->extype & KGDBEXIT_TYPEMASK) {
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	case KGDBEXIT_KILL:
116*4882a593Smuzhiyun 	case KGDBEXIT_CONTINUE:
117*4882a593Smuzhiyun 		set_msr(msr);
118*4882a593Smuzhiyun 		break;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	case KGDBEXIT_SINGLE:
121*4882a593Smuzhiyun 		regs->msr |= MSR_SE;
122*4882a593Smuzhiyun #if 0
123*4882a593Smuzhiyun 		set_msr(msr | MSR_SE);
124*4882a593Smuzhiyun #endif
125*4882a593Smuzhiyun 		break;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun int
kgdb_trap(struct pt_regs * regs)130*4882a593Smuzhiyun kgdb_trap(struct pt_regs *regs)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	return (regs->trap);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun /* return the value of the CPU registers.
136*4882a593Smuzhiyun  * some of them are non-PowerPC names :(
137*4882a593Smuzhiyun  * they are stored in gdb like:
138*4882a593Smuzhiyun  * struct {
139*4882a593Smuzhiyun  *     u32 gpr[32];
140*4882a593Smuzhiyun  *     f64 fpr[32];
141*4882a593Smuzhiyun  *     u32 pc, ps, cnd, lr; (ps=msr)
142*4882a593Smuzhiyun  *     u32 cnt, xer, mq;
143*4882a593Smuzhiyun  * }
144*4882a593Smuzhiyun  */
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun #define SPACE_REQUIRED	((32*4)+(32*8)+(6*4))
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun int
kgdb_getregs(struct pt_regs * regs,char * buf,int max)149*4882a593Smuzhiyun kgdb_getregs(struct pt_regs *regs, char *buf, int max)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	int i;
152*4882a593Smuzhiyun 	unsigned long *ptr = (unsigned long *)buf;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	if (max < SPACE_REQUIRED)
155*4882a593Smuzhiyun 		kgdb_error(KGDBERR_NOSPACE);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if ((unsigned long)ptr & 3)
158*4882a593Smuzhiyun 		kgdb_error(KGDBERR_ALIGNFAULT);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* General Purpose Regs */
161*4882a593Smuzhiyun 	for (i = 0; i < 32; i++)
162*4882a593Smuzhiyun 		*ptr++ = regs->gpr[i];
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* Floating Point Regs */
165*4882a593Smuzhiyun 	for (i = 0; i < 32; i++) {
166*4882a593Smuzhiyun 		*ptr++ = 0;
167*4882a593Smuzhiyun 		*ptr++ = 0;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
171*4882a593Smuzhiyun 	*ptr++ = regs->nip;
172*4882a593Smuzhiyun 	*ptr++ = regs->msr;
173*4882a593Smuzhiyun 	*ptr++ = regs->ccr;
174*4882a593Smuzhiyun 	*ptr++ = regs->link;
175*4882a593Smuzhiyun 	*ptr++ = regs->ctr;
176*4882a593Smuzhiyun 	*ptr++ = regs->xer;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	return (SPACE_REQUIRED);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun /* set the value of the CPU registers */
182*4882a593Smuzhiyun void
kgdb_putreg(struct pt_regs * regs,int regno,char * buf,int length)183*4882a593Smuzhiyun kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	unsigned long *ptr = (unsigned long *)buf;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if (regno < 0 || regno >= 70)
188*4882a593Smuzhiyun 		kgdb_error(KGDBERR_BADPARAMS);
189*4882a593Smuzhiyun 	else if (regno >= 32 && regno < 64) {
190*4882a593Smuzhiyun 		if (length < 8)
191*4882a593Smuzhiyun 			kgdb_error(KGDBERR_NOSPACE);
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 	else {
194*4882a593Smuzhiyun 		if (length < 4)
195*4882a593Smuzhiyun 			kgdb_error(KGDBERR_NOSPACE);
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	if ((unsigned long)ptr & 3)
199*4882a593Smuzhiyun 		kgdb_error(KGDBERR_ALIGNFAULT);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (regno >= 0 && regno < 32)
202*4882a593Smuzhiyun 		regs->gpr[regno] = *ptr;
203*4882a593Smuzhiyun 	else switch (regno) {
204*4882a593Smuzhiyun 	case 64:	regs->nip = *ptr;	break;
205*4882a593Smuzhiyun 	case 65:	regs->msr = *ptr;	break;
206*4882a593Smuzhiyun 	case 66:	regs->ccr = *ptr;	break;
207*4882a593Smuzhiyun 	case 67:	regs->link = *ptr;	break;
208*4882a593Smuzhiyun 	case 68:	regs->ctr = *ptr;	break;
209*4882a593Smuzhiyun 	case 69:	regs->ctr = *ptr;	break;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	default:
212*4882a593Smuzhiyun 		kgdb_error(KGDBERR_BADPARAMS);
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun void
kgdb_putregs(struct pt_regs * regs,char * buf,int length)217*4882a593Smuzhiyun kgdb_putregs(struct pt_regs *regs, char *buf, int length)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	int i;
220*4882a593Smuzhiyun 	unsigned long *ptr = (unsigned long *)buf;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (length < SPACE_REQUIRED)
223*4882a593Smuzhiyun 		kgdb_error(KGDBERR_NOSPACE);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	if ((unsigned long)ptr & 3)
226*4882a593Smuzhiyun 		kgdb_error(KGDBERR_ALIGNFAULT);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	/*
229*4882a593Smuzhiyun 	 * If the stack pointer has moved, you should pray.
230*4882a593Smuzhiyun 	 * (cause only god can help you).
231*4882a593Smuzhiyun 	 */
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	/* General Purpose Regs */
234*4882a593Smuzhiyun 	for (i = 0; i < 32; i++)
235*4882a593Smuzhiyun 		regs->gpr[i] = *ptr++;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/* Floating Point Regs */
238*4882a593Smuzhiyun 	ptr += 32*2;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	/* pc, msr, cr, lr, ctr, xer, (mq is unused) */
241*4882a593Smuzhiyun 	regs->nip = *ptr++;
242*4882a593Smuzhiyun 	regs->msr = *ptr++;
243*4882a593Smuzhiyun 	regs->ccr = *ptr++;
244*4882a593Smuzhiyun 	regs->link = *ptr++;
245*4882a593Smuzhiyun 	regs->ctr = *ptr++;
246*4882a593Smuzhiyun 	regs->xer = *ptr++;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun /* This function will generate a breakpoint exception.  It is used at the
250*4882a593Smuzhiyun    beginning of a program to sync up with a debugger and can be used
251*4882a593Smuzhiyun    otherwise as a quick means to stop program execution and "break" into
252*4882a593Smuzhiyun    the debugger. */
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun void
kgdb_breakpoint(int argc,char * const argv[])255*4882a593Smuzhiyun kgdb_breakpoint(int argc, char * const argv[])
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	asm("	.globl breakinst\n\
258*4882a593Smuzhiyun 	     breakinst: .long 0x7d821008\n\
259*4882a593Smuzhiyun 	    ");
260*4882a593Smuzhiyun }
261