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