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