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 } 275