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
10void breakinst(void);
11
12int
13kgdb_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
23 return 0;
24}
25
26void
27kgdb_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
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
56
57
58
59
60static struct hard_trap_info
61{
62 unsigned int tt;
63 unsigned char signo;
64} hard_trap_info[] = {
65 { 0x200, SIGSEGV },
66 { 0x300, SIGSEGV },
67 { 0x400, SIGBUS },
68 { 0x500, SIGINT },
69 { 0x600, SIGBUS },
70 { 0x700, SIGTRAP },
71 { 0x800, SIGFPE },
72 { 0x900, SIGALRM },
73 { 0xa00, SIGILL },
74 { 0xb00, SIGILL },
75 { 0xc00, SIGCHLD },
76 { 0xd00, SIGTRAP },
77 { 0xe00, SIGFPE },
78 { 0, 0}
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;
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);
100
101 if (regs->nip == (unsigned long)breakinst) {
102
103 regs->nip += 4;
104 }
105 regs->msr &= ~MSR_SE;
106
107
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
150
151
152
153
154
155
156
157
158
159
160#define SPACE_REQUIRED ((32*4)+(32*8)+(6*4))
161
162#ifdef CONFIG_8260
163
164#define STFDI(n,p) __asm__ __volatile__ ("stfd " #n ",%0" : "=o"(p[2*n]))
165
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
189 for (i = 0; i < 32; i++)
190 *ptr++ = regs->gpr[i];
191
192
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
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
215
216#ifdef CONFIG_8260
217
218#define LFD(n,v) __asm__ __volatile__ ("lfd " #n ",%0" :: "o"(v))
219
220#define LFDI(n,p) __asm__ __volatile__ ("lfd " #n ",%0" :: "o"((p)[2*n]))
221
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
293
294
295
296
297 for (i = 0; i < 32; i++)
298 regs->gpr[i] = *ptr++;
299
300
301#ifdef CONFIG_8260
302 LFDM(ptr);
303#endif
304 ptr += 32*2;
305
306
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
316
317
318
319
320void
321kgdb_breakpoint(int argc, char * const argv[])
322{
323 asm(" .globl breakinst\n\
324 breakinst: .long 0x7d821008\n\
325 ");
326}
327