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

Reply via email to