Modified patch originates from Andy Green <andy@openmoko.com>
[u-boot-openmoko/mini2440.git] / lib_ppc / kgdb.c
blob78c2f0c47588103d01b1e77d6834bbbddcc1e8a3
1 #include <common.h>
2 #include <command.h>
4 #if defined(CONFIG_CMD_KGDB)
6 #include <kgdb.h>
7 #include <asm/signal.h>
8 #include <asm/processor.h>
10 #define PC_REGNUM 64
11 #define SP_REGNUM 1
13 void breakinst(void);
15 int
16 kgdb_setjmp(long *buf)
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;
27 void
28 kgdb_longjmp(long *buf, int val)
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));
39 static inline unsigned long
40 get_msr(void)
42 unsigned long msr;
43 asm volatile("mfmsr %0" : "=r" (msr):);
44 return msr;
47 static inline void
48 set_msr(unsigned long msr)
50 asm volatile("mtmsr %0" : : "r" (msr));
53 /* Convert the SPARC hardware trap type code to a unix signal number. */
55 * This table contains the mapping between PowerPC hardware trap types, and
56 * signals, which are primarily what GDB understands.
58 static struct hard_trap_info
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 */
79 static int
80 computeSignal(unsigned int tt)
82 struct hard_trap_info *ht;
84 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
85 if (ht->tt == tt)
86 return ht->signo;
88 return SIGHUP; /* default for things we don't know about */
91 void
92 kgdb_enter(struct pt_regs *regs, kgdb_data *kdp)
94 unsigned long msr;
96 kdp->private[0] = msr = get_msr();
97 set_msr(msr & ~MSR_EE); /* disable interrupts */
99 if (regs->nip == (unsigned long)breakinst) {
100 /* Skip over breakpoint trap insn */
101 regs->nip += 4;
103 regs->msr &= ~MSR_SE;
105 /* reply to host that an exception has occurred */
106 kdp->sigval = computeSignal(regs->trap);
108 kdp->nregs = 2;
110 kdp->regs[0].num = PC_REGNUM;
111 kdp->regs[0].val = regs->nip;
113 kdp->regs[1].num = SP_REGNUM;
114 kdp->regs[1].val = regs->gpr[SP_REGNUM];
117 void
118 kgdb_exit(struct pt_regs *regs, kgdb_data *kdp)
120 unsigned long msr = kdp->private[0];
122 if (kdp->extype & KGDBEXIT_WITHADDR)
123 regs->nip = kdp->exaddr;
125 switch (kdp->extype & KGDBEXIT_TYPEMASK) {
127 case KGDBEXIT_KILL:
128 case KGDBEXIT_CONTINUE:
129 set_msr(msr);
130 break;
132 case KGDBEXIT_SINGLE:
133 regs->msr |= MSR_SE;
134 #if 0
135 set_msr(msr | MSR_SE);
136 #endif
137 break;
142 kgdb_trap(struct pt_regs *regs)
144 return (regs->trap);
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;
158 #define SPACE_REQUIRED ((32*4)+(32*8)+(6*4))
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
175 kgdb_getregs(struct pt_regs *regs, char *buf, int max)
177 int i;
178 unsigned long *ptr = (unsigned long *)buf;
180 if (max < SPACE_REQUIRED)
181 kgdb_error(KGDBERR_NOSPACE);
183 if ((unsigned long)ptr & 3)
184 kgdb_error(KGDBERR_ALIGNFAULT);
186 /* General Purpose Regs */
187 for (i = 0; i < 32; i++)
188 *ptr++ = regs->gpr[i];
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;
199 #endif
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;
209 return (SPACE_REQUIRED);
212 /* set the value of the CPU registers */
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
230 void
231 kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length)
233 unsigned long *ptr = (unsigned long *)buf;
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);
241 else {
242 if (length < 4)
243 kgdb_error(KGDBERR_NOSPACE);
246 if ((unsigned long)ptr & 3)
247 kgdb_error(KGDBERR_ALIGNFAULT);
249 if (regno >= 0 && regno < 32)
250 regs->gpr[regno] = *ptr;
251 else switch (regno) {
253 #ifdef CONFIG_8260
254 #define caseF(n) \
255 case (n) + 32: LFD(n, *ptr); break;
257 caseF( 0) caseF( 1) caseF( 2) caseF( 3) caseF( 4) caseF( 5) caseF( 6) caseF( 7)
258 caseF( 8) caseF( 9) caseF(10) caseF(11) caseF(12) caseF(13) caseF(14) caseF(15)
259 caseF(16) caseF(17) caseF(18) caseF(19) caseF(20) caseF(21) caseF(22) caseF(23)
260 caseF(24) caseF(25) caseF(26) caseF(27) caseF(28) caseF(29) caseF(30) caseF(31)
262 #undef caseF
263 #endif
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;
272 default:
273 kgdb_error(KGDBERR_BADPARAMS);
277 void
278 kgdb_putregs(struct pt_regs *regs, char *buf, int length)
280 int i;
281 unsigned long *ptr = (unsigned long *)buf;
283 if (length < SPACE_REQUIRED)
284 kgdb_error(KGDBERR_NOSPACE);
286 if ((unsigned long)ptr & 3)
287 kgdb_error(KGDBERR_ALIGNFAULT);
290 * If the stack pointer has moved, you should pray.
291 * (cause only god can help you).
294 /* General Purpose Regs */
295 for (i = 0; i < 32; i++)
296 regs->gpr[i] = *ptr++;
298 /* Floating Point Regs */
299 #ifdef CONFIG_8260
300 LFDM(ptr);
301 #endif
302 ptr += 32*2;
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++;
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. */
318 void
319 kgdb_breakpoint(int argc, char *argv[])
321 asm(" .globl breakinst\n\
322 breakinst: .long 0x7d821008\n\
326 #endif