Home | History | Annotate | Download | only in lib
      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 },			/* alignment */
     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