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