]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/powerpc/lib/kgdb.c
powerpc: mpc8260: consolidate CONFIG_MPC8260 and CONFIG_8260
[karo-tx-uboot.git] / arch / powerpc / lib / kgdb.c
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         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));
22         /* XXX should save fp regs as well */
23         return 0;
24 }
25
26 void
27 kgdb_longjmp(long *buf, int val)
28 {
29         unsigned long temp;
30
31         if (val == 0)
32                 val = 1;
33
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));
39 }
40
41 static inline unsigned long
42 get_msr(void)
43 {
44         unsigned long msr;
45         asm volatile("mfmsr %0" : "=r" (msr):);
46         return msr;
47 }
48
49 static inline void
50 set_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  */
60 static 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
81 static int
82 computeSignal(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
93 void
94 kgdb_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
119 void
120 kgdb_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
143 int
144 kgdb_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_MPC8260
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
176 int
177 kgdb_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_MPC8260
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_MPC8260
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
232 void
233 kgdb_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_MPC8260
256 #define caseF(n) \
257         case (n) + 32:  LFD(n, *ptr);           break;
258
259 caseF( 0) caseF( 1) caseF( 2) caseF( 3) caseF( 4) caseF( 5) caseF( 6) caseF( 7)
260 caseF( 8) caseF( 9) caseF(10) caseF(11) caseF(12) caseF(13) caseF(14) caseF(15)
261 caseF(16) caseF(17) caseF(18) caseF(19) caseF(20) caseF(21) caseF(22) caseF(23)
262 caseF(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
279 void
280 kgdb_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_MPC8260
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
320 void
321 kgdb_breakpoint(int argc, char * const argv[])
322 {
323         asm("   .globl breakinst\n\
324              breakinst: .long 0x7d821008\n\
325             ");
326 }