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