Merge branch 'master' of git://git.denx.de/u-boot-samsung
[platform/kernel/u-boot.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 int
163 kgdb_getregs(struct pt_regs *regs, char *buf, int max)
164 {
165         int i;
166         unsigned long *ptr = (unsigned long *)buf;
167
168         if (max < SPACE_REQUIRED)
169                 kgdb_error(KGDBERR_NOSPACE);
170
171         if ((unsigned long)ptr & 3)
172                 kgdb_error(KGDBERR_ALIGNFAULT);
173
174         /* General Purpose Regs */
175         for (i = 0; i < 32; i++)
176                 *ptr++ = regs->gpr[i];
177
178         /* Floating Point Regs */
179         for (i = 0; i < 32; i++) {
180                 *ptr++ = 0;
181                 *ptr++ = 0;
182         }
183
184         /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
185         *ptr++ = regs->nip;
186         *ptr++ = regs->msr;
187         *ptr++ = regs->ccr;
188         *ptr++ = regs->link;
189         *ptr++ = regs->ctr;
190         *ptr++ = regs->xer;
191
192         return (SPACE_REQUIRED);
193 }
194
195 /* set the value of the CPU registers */
196 void
197 kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length)
198 {
199         unsigned long *ptr = (unsigned long *)buf;
200
201         if (regno < 0 || regno >= 70)
202                 kgdb_error(KGDBERR_BADPARAMS);
203         else if (regno >= 32 && regno < 64) {
204                 if (length < 8)
205                         kgdb_error(KGDBERR_NOSPACE);
206         }
207         else {
208                 if (length < 4)
209                         kgdb_error(KGDBERR_NOSPACE);
210         }
211
212         if ((unsigned long)ptr & 3)
213                 kgdb_error(KGDBERR_ALIGNFAULT);
214
215         if (regno >= 0 && regno < 32)
216                 regs->gpr[regno] = *ptr;
217         else switch (regno) {
218         case 64:        regs->nip = *ptr;       break;
219         case 65:        regs->msr = *ptr;       break;
220         case 66:        regs->ccr = *ptr;       break;
221         case 67:        regs->link = *ptr;      break;
222         case 68:        regs->ctr = *ptr;       break;
223         case 69:        regs->ctr = *ptr;       break;
224
225         default:
226                 kgdb_error(KGDBERR_BADPARAMS);
227         }
228 }
229
230 void
231 kgdb_putregs(struct pt_regs *regs, char *buf, int length)
232 {
233         int i;
234         unsigned long *ptr = (unsigned long *)buf;
235
236         if (length < SPACE_REQUIRED)
237                 kgdb_error(KGDBERR_NOSPACE);
238
239         if ((unsigned long)ptr & 3)
240                 kgdb_error(KGDBERR_ALIGNFAULT);
241
242         /*
243          * If the stack pointer has moved, you should pray.
244          * (cause only god can help you).
245          */
246
247         /* General Purpose Regs */
248         for (i = 0; i < 32; i++)
249                 regs->gpr[i] = *ptr++;
250
251         /* Floating Point Regs */
252         ptr += 32*2;
253
254         /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
255         regs->nip = *ptr++;
256         regs->msr = *ptr++;
257         regs->ccr = *ptr++;
258         regs->link = *ptr++;
259         regs->ctr = *ptr++;
260         regs->xer = *ptr++;
261 }
262
263 /* This function will generate a breakpoint exception.  It is used at the
264    beginning of a program to sync up with a debugger and can be used
265    otherwise as a quick means to stop program execution and "break" into
266    the debugger. */
267
268 void
269 kgdb_breakpoint(int argc, char * const argv[])
270 {
271         asm("   .globl breakinst\n\
272              breakinst: .long 0x7d821008\n\
273             ");
274 }