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