Signed-off-by: Tonny Tzeng <tonny.tz...@gmail.com> --- arch/arm/include/asm/kgdb.h | 66 +++++++++++++++ arch/arm/lib/Makefile | 1 + arch/arm/lib/kgdb.c | 194 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 261 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/kgdb.h create mode 100644 arch/arm/lib/kgdb.c
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h new file mode 100644 index 0000000..dfca31c --- /dev/null +++ b/arch/arm/include/asm/kgdb.h @@ -0,0 +1,66 @@ +/* + * ARM KGDB support + * + * Author: Deepak Saxena <dsax...@mvista.com> + * + * Copyright (C) 2002 MontaVista Software Inc. + * + */ +#ifndef __ARM_KGDB_H__ +#define __ARM_KGDB_H__ + +#define BREAK_INSTR_SIZE 4 +#define KGDB_COMPILED_BREAK 0xe7ffdeff + +#ifndef __ASSEMBLY__ + +static inline void arch_kgdb_breakpoint(void) +{ + asm(".word 0xe7ffdeff"); +} + +#endif /* !__ASSEMBLY__ */ + +/* + * From Kevin Hilman: + * + * gdb is expecting the following registers layout. + * + * r0-r15: 1 long word each + * f0-f7: unused, 3 long words each !! + * fps: unused, 1 long word + * cpsr: 1 long word + * + * Even though f0-f7 and fps are not used, they need to be + * present in the registers sent for correct processing in + * the host-side gdb. + * + * In particular, it is crucial that CPSR is in the right place, + * otherwise gdb will not be able to correctly interpret stepping over + * conditional branches. + */ +#define _GP_REGS 16 +#define _FP_REGS 8 +#define _EXTRA_REGS 2 +#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) + +#define _R0 0 +#define _R1 1 +#define _R2 2 +#define _R3 3 +#define _R4 4 +#define _R5 5 +#define _R6 6 +#define _R7 7 +#define _R8 8 +#define _R9 9 +#define _R10 10 +#define _FP 11 +#define _IP 12 +#define _SPT 13 +#define _LR 14 +#define _PC 15 +#define _CPSR (GDB_MAX_REGS - 1) + +#endif /* __ASM_KGDB_H__ */ + diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 0293348..36fe528 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -44,6 +44,7 @@ COBJS-y += cache-cp15.o endif COBJS-y += interrupts.o COBJS-y += reset.o +COBJS-$(CONFIG_CMD_KGDB) += kgdb.o SRCS := $(GLSOBJS:.o=.S) $(GLCOBJS:.o=.c) \ $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) diff --git a/arch/arm/lib/kgdb.c b/arch/arm/lib/kgdb.c new file mode 100644 index 0000000..f7044f6 --- /dev/null +++ b/arch/arm/lib/kgdb.c @@ -0,0 +1,194 @@ +#include <common.h> +#include <asm-generic/signal.h> +#include <kgdb.h> + +/* + * kgdb_breakpoint - generate breakpoint exception + * + * This function will generate a breakpoint exception. It is used at the + * beginning of a program to sync up with a debugger and can be used + * otherwise as a quick means to stop program execution and "break" into + * the debugger. + */ +void kgdb_breakpoint (int argc, char *argv[]) +{ + arch_kgdb_breakpoint(); +} + +int kgdb_setjmp(long *buf) +{ + asm(" stmia r0, {r0-r14}\n \ + str lr,[r0, #60]\n \ + mrs r1,cpsr\n \ + str r1,[r0,#64]\n \ + ldr r1,[r0,#4]\n \ + "); + return 0; +} + +void kgdb_longjmp(long *buf, int val) +{ + asm(" str r1,[r0]\n \ + ldr r1,[r0, #64]\n \ + msr spsr,r1\n \ + ldmia r0,{r0-pc}^\n \ + "); +} + +int kgdb_trap(struct pt_regs *regs) +{ + return SIGTRAP; +} + +void kgdb_enter(struct pt_regs *regs, kgdb_data *kdp) +{ + kdp->sigval = kgdb_trap(regs); + kdp->nregs = 0; +} + +void kgdb_exit(struct pt_regs *regs, kgdb_data *kdp) +{ +} + +int kgdb_getregs(struct pt_regs *regs, char *buf, int max) +{ + int i; + unsigned long *gdb_regs = (unsigned long *)buf; + + if (max < (GDB_MAX_REGS * sizeof(unsigned long))) + kgdb_error(KGDBERR_NOSPACE); + + /* Initialize all to zero. */ + for (i = 0; i < GDB_MAX_REGS; i++) + gdb_regs[i] = 0; + + gdb_regs[_R0] = regs->ARM_r0; + gdb_regs[_R1] = regs->ARM_r1; + gdb_regs[_R2] = regs->ARM_r2; + gdb_regs[_R3] = regs->ARM_r3; + gdb_regs[_R4] = regs->ARM_r4; + gdb_regs[_R5] = regs->ARM_r5; + gdb_regs[_R6] = regs->ARM_r6; + gdb_regs[_R7] = regs->ARM_r7; + gdb_regs[_R8] = regs->ARM_r8; + gdb_regs[_R9] = regs->ARM_r9; + gdb_regs[_R10] = regs->ARM_r10; + gdb_regs[_FP] = regs->ARM_fp; + gdb_regs[_IP] = regs->ARM_ip; + gdb_regs[_SPT] = regs->ARM_sp; + gdb_regs[_LR] = regs->ARM_lr; + gdb_regs[_PC] = regs->ARM_pc; + gdb_regs[_CPSR] = regs->ARM_cpsr; + + return GDB_MAX_REGS *sizeof(unsigned long); +} + +void kgdb_putreg(struct pt_regs *regs, int regno, char *buf, int length) +{ + unsigned long val, *ptr = (unsigned long *)buf; + + if (regno < 0 || GDB_MAX_REGS <= regno) + kgdb_error(KGDBERR_BADPARAMS); + else { + if (length < 4) + kgdb_error(KGDBERR_NOSPACE); + } + if ((unsigned long)ptr & 3) + kgdb_error(KGDBERR_ALIGNFAULT); + else + val = *ptr; + + switch (regno) { + case _R0: + regs->ARM_r0 = val; break; + case _R1: + regs->ARM_r1 = val; break; + case _R2: + regs->ARM_r2 = val; break; + case _R3: + regs->ARM_r3 = val; break; + case _R4: + regs->ARM_r4 = val; break; + case _R5: + regs->ARM_r5 = val; break; + case _R6: + regs->ARM_r6 = val; break; + case _R7: + regs->ARM_r7 = val; break; + case _R8: + regs->ARM_r8 = val; break; + case _R9: + regs->ARM_r9 = val; break; + case _R10: + regs->ARM_r10 = val; break; + case _FP: + regs->ARM_fp = val; break; + case _IP: + regs->ARM_ip = val; break; + case _SPT: + regs->ARM_sp = val; break; + case _LR: + regs->ARM_lr = val; break; + case _PC: + regs->ARM_pc = val; break; + case 0x19: + regs->ARM_cpsr = val; 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 < (GDB_MAX_REGS *sizeof(unsigned long))) + kgdb_error(KGDBERR_NOSPACE); + + if ((unsigned long)gdb_regs & 3) + kgdb_error(KGDBERR_ALIGNFAULT); + + regs->ARM_r0 = gdb_regs[_R0]; + regs->ARM_r1 = gdb_regs[_R1]; + regs->ARM_r2 = gdb_regs[_R2]; + regs->ARM_r3 = gdb_regs[_R3]; + regs->ARM_r4 = gdb_regs[_R4]; + regs->ARM_r5 = gdb_regs[_R5]; + regs->ARM_r6 = gdb_regs[_R6]; + regs->ARM_r7 = gdb_regs[_R7]; + regs->ARM_r8 = gdb_regs[_R8]; + regs->ARM_r9 = gdb_regs[_R9]; + regs->ARM_r10 = gdb_regs[_R10]; + regs->ARM_fp = gdb_regs[_FP]; + regs->ARM_ip = gdb_regs[_IP]; + regs->ARM_sp = gdb_regs[_SPT]; + regs->ARM_lr = gdb_regs[_LR]; + regs->ARM_pc = gdb_regs[_PC]; + regs->ARM_cpsr = gdb_regs[_CPSR]; +} + +void kgdb_interruptible(int yes) +{ +#ifdef CONFIG_USE_IRQ + if (yes) + enable_interrupts(); + else + disable_interrupts(); +#endif +} + +void arch_kgdb_set_sw_break(struct kgdb_bkpt *bkpt) +{ + int addr = bkpt->bpt_addr; + memcpy(bkpt->saved_instr, (unsigned long *)addr, BREAK_INSTR_SIZE); + *(unsigned long *)addr = KGDB_COMPILED_BREAK; + kgdb_flush_cache_all(); +} + +void arch_kgdb_remove_sw_break(struct kgdb_bkpt *bkpt) +{ + int addr = bkpt->bpt_addr; + memcpy((unsigned long *)addr, bkpt->saved_instr, BREAK_INSTR_SIZE); + kgdb_flush_cache_all(); +} + -- 1.6.0.6 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot