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