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