diff options
Diffstat (limited to 'arch/blackfin/lib/kgdb.c')
| -rw-r--r-- | arch/blackfin/lib/kgdb.c | 423 | 
1 files changed, 423 insertions, 0 deletions
| diff --git a/arch/blackfin/lib/kgdb.c b/arch/blackfin/lib/kgdb.c new file mode 100644 index 000000000..bd62d7105 --- /dev/null +++ b/arch/blackfin/lib/kgdb.c @@ -0,0 +1,423 @@ +/* + * U-boot - architecture specific kgdb code + * + * Copyright 2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <common.h> +#include <command.h> + +#include <kgdb.h> +#include <asm/processor.h> +#include <asm/mach-common/bits/core.h> +#include "kgdb.h" +#include <asm/deferred.h> +#include <asm/traps.h> +#include <asm/signal.h> + +void kgdb_enter(struct pt_regs *regs, kgdb_data *kdp) +{ +	/* disable interrupts */ +	disable_interrupts(); + +	/* reply to host that an exception has occurred */ +	kdp->sigval = kgdb_trap(regs); + +	/* send the PC and the Stack Pointer */ +	kdp->nregs = 2; +	kdp->regs[0].num = BFIN_PC; +	kdp->regs[0].val = regs->pc; + +	kdp->regs[1].num = BFIN_SP; +	kdp->regs[1].val = (unsigned long)regs; + +} + +void kgdb_exit(struct pt_regs *regs, kgdb_data *kdp) +{ +	if (kdp->extype & KGDBEXIT_WITHADDR) +		printf("KGDBEXIT_WITHADDR\n"); + +	switch (kdp->extype & KGDBEXIT_TYPEMASK) { +	case KGDBEXIT_KILL: +		printf("KGDBEXIT_KILL:\n"); +		break; +	case KGDBEXIT_CONTINUE: +		/* Make sure the supervisor single step bit is clear */ +		regs->syscfg &= ~1; +		break; +	case KGDBEXIT_SINGLE: +		/* set the supervisor single step bit */ +		regs->syscfg |= 1; +		break; +	default: +		printf("KGDBEXIT : %d\n", kdp->extype); +	} + +	/* enable interrupts */ +	enable_interrupts(); +} + +int kgdb_trap(struct pt_regs *regs) +{ +	/* ipend doesn't get filled in properly */ +	switch (regs->seqstat & EXCAUSE) { +	case VEC_EXCPT01: +		return SIGTRAP; +	case VEC_EXCPT03: +		return SIGSEGV; +	case VEC_EXCPT02: +		return SIGTRAP; +	case VEC_EXCPT04 ... VEC_EXCPT15: +		return SIGILL; +	case VEC_STEP: +		return SIGTRAP; +	case VEC_OVFLOW: +		return SIGTRAP; +	case VEC_UNDEF_I: +		return SIGILL; +	case VEC_ILGAL_I: +		return SIGILL; +	case VEC_CPLB_VL: +		return SIGSEGV; +	case VEC_MISALI_D: +		return SIGBUS; +	case VEC_UNCOV: +		return SIGILL; +	case VEC_CPLB_MHIT: +		return SIGSEGV; +	case VEC_MISALI_I: +		return SIGBUS; +	case VEC_CPLB_I_VL: +		return SIGBUS; +	case VEC_CPLB_I_MHIT: +		return SIGSEGV; +	default: +		return SIGBUS; +	} +} + +/* + * getregs - gets the pt_regs, and gives them to kgdb's buffer + */ +int kgdb_getregs(struct pt_regs *regs, char *buf, int max) +{ +	unsigned long *gdb_regs = (unsigned long *)buf; + +	if (max < NUMREGBYTES) +		kgdb_error(KGDBERR_NOSPACE); + +	if ((unsigned long)gdb_regs & 3) +		kgdb_error(KGDBERR_ALIGNFAULT); + +	gdb_regs[BFIN_R0] = regs->r0; +	gdb_regs[BFIN_R1] = regs->r1; +	gdb_regs[BFIN_R2] = regs->r2; +	gdb_regs[BFIN_R3] = regs->r3; +	gdb_regs[BFIN_R4] = regs->r4; +	gdb_regs[BFIN_R5] = regs->r5; +	gdb_regs[BFIN_R6] = regs->r6; +	gdb_regs[BFIN_R7] = regs->r7; +	gdb_regs[BFIN_P0] = regs->p0; +	gdb_regs[BFIN_P1] = regs->p1; +	gdb_regs[BFIN_P2] = regs->p2; +	gdb_regs[BFIN_P3] = regs->p3; +	gdb_regs[BFIN_P4] = regs->p4; +	gdb_regs[BFIN_P5] = regs->p5; +	gdb_regs[BFIN_SP] = (unsigned long)regs; +	gdb_regs[BFIN_FP] = regs->fp; +	gdb_regs[BFIN_I0] = regs->i0; +	gdb_regs[BFIN_I1] = regs->i1; +	gdb_regs[BFIN_I2] = regs->i2; +	gdb_regs[BFIN_I3] = regs->i3; +	gdb_regs[BFIN_M0] = regs->m0; +	gdb_regs[BFIN_M1] = regs->m1; +	gdb_regs[BFIN_M2] = regs->m2; +	gdb_regs[BFIN_M3] = regs->m3; +	gdb_regs[BFIN_B0] = regs->b0; +	gdb_regs[BFIN_B1] = regs->b1; +	gdb_regs[BFIN_B2] = regs->b2; +	gdb_regs[BFIN_B3] = regs->b3; +	gdb_regs[BFIN_L0] = regs->l0; +	gdb_regs[BFIN_L1] = regs->l1; +	gdb_regs[BFIN_L2] = regs->l2; +	gdb_regs[BFIN_L3] = regs->l3; +	gdb_regs[BFIN_A0_DOT_X] = regs->a0x; +	gdb_regs[BFIN_A0_DOT_W] = regs->a0w; +	gdb_regs[BFIN_A1_DOT_X] = regs->a1x; +	gdb_regs[BFIN_A1_DOT_W] = regs->a1w; +	gdb_regs[BFIN_ASTAT] = regs->astat; +	gdb_regs[BFIN_RETS] = regs->rets; +	gdb_regs[BFIN_LC0] = regs->lc0; +	gdb_regs[BFIN_LT0] = regs->lt0; +	gdb_regs[BFIN_LB0] = regs->lb0; +	gdb_regs[BFIN_LC1] = regs->lc1; +	gdb_regs[BFIN_LT1] = regs->lt1; +	gdb_regs[BFIN_LB1] = regs->lb1; +	gdb_regs[BFIN_CYCLES] = 0; +	gdb_regs[BFIN_CYCLES2] = 0; +	gdb_regs[BFIN_USP] = regs->usp; +	gdb_regs[BFIN_SEQSTAT] = regs->seqstat; +	gdb_regs[BFIN_SYSCFG] = regs->syscfg; +	gdb_regs[BFIN_RETI] = regs->pc; +	gdb_regs[BFIN_RETX] = regs->retx; +	gdb_regs[BFIN_RETN] = regs->retn; +	gdb_regs[BFIN_RETE] = regs->rete; +	gdb_regs[BFIN_PC] = regs->pc; +	gdb_regs[BFIN_CC] = 0; +	gdb_regs[BFIN_EXTRA1] = 0; +	gdb_regs[BFIN_EXTRA2] = 0; +	gdb_regs[BFIN_EXTRA3] = 0; +	gdb_regs[BFIN_IPEND] = regs->ipend; + +	return NUMREGBYTES; +} + +/* + * putreg - put kgdb's reg (regno) into the pt_regs + */ +void kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length) +{ +	unsigned long *ptr = (unsigned long *)buf; + +	if (regno < 0 || regno > BFIN_NUM_REGS) +		kgdb_error(KGDBERR_BADPARAMS); + +	if (length < 4) +		kgdb_error(KGDBERR_NOSPACE); + +	if ((unsigned long)ptr & 3) +		kgdb_error(KGDBERR_ALIGNFAULT); + +	switch (regno) { +	case BFIN_R0: +		regs->r0 = *ptr; +		break; +	case BFIN_R1: +		regs->r1 = *ptr; +		break; +	case BFIN_R2: +		regs->r2 = *ptr; +		break; +	case BFIN_R3: +		regs->r3 = *ptr; +		break; +	case BFIN_R4: +		regs->r4 = *ptr; +		break; +	case BFIN_R5: +		regs->r5 = *ptr; +		break; +	case BFIN_R6: +		regs->r6 = *ptr; +		break; +	case BFIN_R7: +		regs->r7 = *ptr; +		break; +	case BFIN_P0: +		regs->p0 = *ptr; +		break; +	case BFIN_P1: +		regs->p1 = *ptr; +		break; +	case BFIN_P2: +		regs->p2 = *ptr; +		break; +	case BFIN_P3: +		regs->p3 = *ptr; +		break; +	case BFIN_P4: +		regs->p4 = *ptr; +		break; +	case BFIN_P5: +		regs->p5 = *ptr; +		break; +	case BFIN_SP: +		regs->reserved = *ptr; +		break; +	case BFIN_FP: +		regs->fp = *ptr; +		break; +	case BFIN_I0: +		regs->i0 = *ptr; +		break; +	case BFIN_I1: +		regs->i1 = *ptr; +		break; +	case BFIN_I2: +		regs->i2 = *ptr; +		break; +	case BFIN_I3: +		regs->i3 = *ptr; +		break; +	case BFIN_M0: +		regs->m0 = *ptr; +		break; +	case BFIN_M1: +		regs->m1 = *ptr; +		break; +	case BFIN_M2: +		regs->m2 = *ptr; +		break; +	case BFIN_M3: +		regs->m3 = *ptr; +		break; +	case BFIN_B0: +		regs->b0 = *ptr; +		break; +	case BFIN_B1: +		regs->b1 = *ptr; +		break; +	case BFIN_B2: +		regs->b2 = *ptr; +		break; +	case BFIN_B3: +		regs->b3 = *ptr; +		break; +	case BFIN_L0: +		regs->l0 = *ptr; +		break; +	case BFIN_L1: +		regs->l1 = *ptr; +		break; +	case BFIN_L2: +		regs->l2 = *ptr; +		break; +	case BFIN_L3: +		regs->l3 = *ptr; +		break; +	case BFIN_A0_DOT_X: +		regs->a0x = *ptr; +		break; +	case BFIN_A0_DOT_W: +		regs->a0w = *ptr; +		break; +	case BFIN_A1_DOT_X: +		regs->a1x = *ptr; +		break; +	case BFIN_A1_DOT_W: +		regs->a1w = *ptr; +		break; +	case BFIN_ASTAT: +		regs->astat = *ptr; +		break; +	case BFIN_RETS: +		regs->rets = *ptr; +		break; +	case BFIN_LC0: +		regs->lc0 = *ptr; +		break; +	case BFIN_LT0: +		regs->lt0 = *ptr; +		break; +	case BFIN_LB0: +		regs->lb0 = *ptr; +		break; +	case BFIN_LC1: +		regs->lc1 = *ptr; +		break; +	case BFIN_LT1: +		regs->lt1 = *ptr; +		break; +	case BFIN_LB1: +		regs->lb1 = *ptr; +		break; +/* +  BFIN_CYCLES, +  BFIN_CYCLES2, +  BFIN_USP, +  BFIN_SEQSTAT, +  BFIN_SYSCFG, +*/ +	case BFIN_RETX: +		regs->retx = *ptr; +		break; +	case BFIN_RETN: +		regs->retn = *ptr; +		break; +	case BFIN_RETE: +		regs->rete = *ptr; +		break; +	case BFIN_PC: +		regs->pc = *ptr; +		break; + +	default: +		kgdb_error(KGDBERR_BADPARAMS); +	} +} + +void kgdb_putregs(struct pt_regs *regs, char *buf, int length) +{ +	unsigned long *gdb_regs = (unsigned long *)buf; + +	if (length != BFIN_NUM_REGS) +		kgdb_error(KGDBERR_NOSPACE); + +	if ((unsigned long)gdb_regs & 3) +		kgdb_error(KGDBERR_ALIGNFAULT); + +	regs->r0 = gdb_regs[BFIN_R0]; +	regs->r1 = gdb_regs[BFIN_R1]; +	regs->r2 = gdb_regs[BFIN_R2]; +	regs->r3 = gdb_regs[BFIN_R3]; +	regs->r4 = gdb_regs[BFIN_R4]; +	regs->r5 = gdb_regs[BFIN_R5]; +	regs->r6 = gdb_regs[BFIN_R6]; +	regs->r7 = gdb_regs[BFIN_R7]; +	regs->p0 = gdb_regs[BFIN_P0]; +	regs->p1 = gdb_regs[BFIN_P1]; +	regs->p2 = gdb_regs[BFIN_P2]; +	regs->p3 = gdb_regs[BFIN_P3]; +	regs->p4 = gdb_regs[BFIN_P4]; +	regs->p5 = gdb_regs[BFIN_P5]; +	regs->fp = gdb_regs[BFIN_FP]; +/*	regs->sp = gdb_regs[BFIN_ ]; */ +	regs->i0 = gdb_regs[BFIN_I0]; +	regs->i1 = gdb_regs[BFIN_I1]; +	regs->i2 = gdb_regs[BFIN_I2]; +	regs->i3 = gdb_regs[BFIN_I3]; +	regs->m0 = gdb_regs[BFIN_M0]; +	regs->m1 = gdb_regs[BFIN_M1]; +	regs->m2 = gdb_regs[BFIN_M2]; +	regs->m3 = gdb_regs[BFIN_M3]; +	regs->b0 = gdb_regs[BFIN_B0]; +	regs->b1 = gdb_regs[BFIN_B1]; +	regs->b2 = gdb_regs[BFIN_B2]; +	regs->b3 = gdb_regs[BFIN_B3]; +	regs->l0 = gdb_regs[BFIN_L0]; +	regs->l1 = gdb_regs[BFIN_L1]; +	regs->l2 = gdb_regs[BFIN_L2]; +	regs->l3 = gdb_regs[BFIN_L3]; +	regs->a0x = gdb_regs[BFIN_A0_DOT_X]; +	regs->a0w = gdb_regs[BFIN_A0_DOT_W]; +	regs->a1x = gdb_regs[BFIN_A1_DOT_X]; +	regs->a1w = gdb_regs[BFIN_A1_DOT_W]; +	regs->rets = gdb_regs[BFIN_RETS]; +	regs->lc0 = gdb_regs[BFIN_LC0]; +	regs->lt0 = gdb_regs[BFIN_LT0]; +	regs->lb0 = gdb_regs[BFIN_LB0]; +	regs->lc1 = gdb_regs[BFIN_LC1]; +	regs->lt1 = gdb_regs[BFIN_LT1]; +	regs->lb1 = gdb_regs[BFIN_LB1]; +	regs->usp = gdb_regs[BFIN_USP]; +	regs->syscfg = gdb_regs[BFIN_SYSCFG]; +	regs->retx = gdb_regs[BFIN_PC]; +	regs->retn = gdb_regs[BFIN_RETN]; +	regs->rete = gdb_regs[BFIN_RETE]; +	regs->pc = gdb_regs[BFIN_PC]; + +#if 0	/* can't change these */ +	regs->astat = gdb_regs[BFIN_ASTAT]; +	regs->seqstat = gdb_regs[BFIN_SEQSTAT]; +	regs->ipend = gdb_regs[BFIN_IPEND]; +#endif + +} + +void kgdb_breakpoint(int argc, char *argv[]) +{ +	asm volatile ("excpt 0x1\n"); +} |