[U-Boot] [PATCH] arm920t kgdb serial support
barbalace at igi.cnr.it
barbalace at igi.cnr.it
Tue May 5 21:21:21 CEST 2009
This patch add kgdb to ARM920T cpus (full support to s3c2440).
The patch lets debugging remote ARM targets using the serial
line and GDB.
Signed-off-by: Antonio Barbalace <antonio.barbalace at igi.cnr.it>
diff -r -u u-boot/common/kgdb.c u-boot-UniPd-denx.de/common/kgdb.c
--- u-boot/common/kgdb.c 2007-11-06 18:07:07.000000000 +0100
+++ u-boot-UniPd-denx.de/common/kgdb.c 2009-05-05 18:44:25.000000000 +0200
@@ -458,6 +458,7 @@
goto doexit;
+#ifdef _PPC
case 'S': /* SSS single step with signal SS */
*ptr = '\0'; /* ignore the signal number for now */
/* fall through */
@@ -469,7 +470,7 @@
kd.exaddr = addr;
kd.extype |= KGDBEXIT_WITHADDR;
}
-
+#endif
doexit:
/* Need to flush the instruction cache here, as we may have deposited a
* breakpoint, and the icache probably has no way of knowing that a
data ref to
@@ -496,8 +497,13 @@
} else {
kgdb_error(KGDBERR_BADPARAMS);
}
+
+ case 'q':
+ if (!(strcmp(ptr, "Supported"))) {
+ sprintf(remcomOutBuffer, "PacketSize=%d", BUFMAX);
+ }
break;
- } /* switch */
+ } /* switch */
if (errnum != 0)
sprintf(remcomOutBuffer, "E%02d", errnum);
diff -r -u u-boot/cpu/arm920t/Makefile
u-boot-UniPd-denx.de/cpu/arm920t/Makefile
--- u-boot/cpu/arm920t/Makefile 2007-11-07 17:18:30.000000000 +0100
+++ u-boot-UniPd-denx.de/cpu/arm920t/Makefile 2009-01-15
17:01:58.000000000 +0100
@@ -26,7 +26,8 @@
LIB = $(obj)lib$(CPU).a
START = start.o
-COBJS = cpu.o interrupts.o
+COBJS = cpu.o interrupts.o
+SOBJS = kgdb.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))
diff -r -u u-boot/cpu/arm920t/interrupts.c
u-boot-UniPd-denx.de/cpu/arm920t/interrupts.c
--- u-boot/cpu/arm920t/interrupts.c 2007-11-06 18:11:29.000000000 +0100
+++ u-boot-UniPd-denx.de/cpu/arm920t/interrupts.c 2009-05-05
18:52:15.000000000 +0200
@@ -33,6 +33,10 @@
#include <arm920t.h>
#include <asm/proc-armv/ptrace.h>
+#if defined(CONFIG_CMD_KGDB)
+int (*debugger_exception_handler)(struct pt_regs *) = 0;
+#endif
+
#ifdef CONFIG_USE_IRQ
/* enable IRQ interrupts */
void enable_interrupts (void)
@@ -119,9 +123,16 @@
void do_undefined_instruction (struct pt_regs *pt_regs)
{
+#if defined(CONFIG_CMD_KGDB)
+ pt_regs->ARM_pc -= 4;
+ if (debugger_exception_handler && (*debugger_exception_handler)(pt_regs)) {
+ return;
+ }
+#else
printf ("undefined instruction\n");
show_regs (pt_regs);
bad_mode ();
+#endif
}
void do_software_interrupt (struct pt_regs *pt_regs)
diff -r -u u-boot/cpu/arm920t/s3c24x0/serial.c
u-boot-UniPd-denx.de/cpu/arm920t/s3c24x0/serial.c
--- u-boot/cpu/arm920t/s3c24x0/serial.c 2007-11-06 18:13:13.000000000 +0100
+++ u-boot-UniPd-denx.de/cpu/arm920t/s3c24x0/serial.c 2009-05-05
19:00:14.000000000 +0200
@@ -306,6 +306,114 @@
#endif /* CONFIG_SERIAL_MULTI */
+#if defined(CONFIG_CMD_KGDB)
+/*
+ according to CONFIG_KGDB_SER_INDEX kgdb uses serial port
+ number 0 or number 1
+ - if CONFIG_KGDB_SER_INDEX = 1 => serial port number 0 :
+ configuration has been already done
+ - if CONFIG_KGDB_SER_INDEX = 2 => serial port number 1 :
+ configure port 1 for serial I/O with rate = CONFIG_KGDB_BAUDRATE
+*/
+#if (CONFIG_KGDB_SER_INDEX & 2)
+void kgdb_serial_init (void)
+{
+ volatile char val;
+ unsigned short br_reg;
+
+ get_clocks ();
+ br_reg = (((((gd->cpu_clk / 16) / 18) * 10) / CONFIG_KGDB_BAUDRATE) +
+ 5) / 10;
+ /*
+ * Init onboard 16550 UART
+ */
+ out8 (ACTING_UART1_BASE + UART_LCR, 0x80); /* set DLAB bit */
+ out8 (ACTING_UART1_BASE + UART_DLL, (br_reg & 0x00ff)); /* set
divisor for 9600 baud */
+ out8 (ACTING_UART1_BASE + UART_DLM, ((br_reg & 0xff00) >> 8)); /*
set divisor for 9600 baud */
+ out8 (ACTING_UART1_BASE + UART_LCR, 0x03); /* line control 8 bits no
parity */
+ out8 (ACTING_UART1_BASE + UART_FCR, 0x00); /* disable FIFO */
+ out8 (ACTING_UART1_BASE + UART_MCR, 0x00); /* no modem control DTR RTS */
+ val = in8 (ACTING_UART1_BASE + UART_LSR); /* clear line status */
+ val = in8 (ACTING_UART1_BASE + UART_RBR); /* read receive buffer */
+ out8 (ACTING_UART1_BASE + UART_SCR, 0x00); /* set scratchpad */
+ out8 (ACTING_UART1_BASE + UART_IER, 0x00); /* set interrupt enable reg */
+}
+
+void putDebugChar (const char c)
+{
+ if (c == '\n')
+ serial_putc ('\r');
+
+ out8 (ACTING_UART1_BASE + UART_THR, c); /* put character out */
+
+ /* check THRE bit, wait for transfer done */
+ while ((in8 (ACTING_UART1_BASE + UART_LSR) & 0x20) != 0x20);
+}
+
+void putDebugStr (const char *s)
+{
+ while (*s) {
+ serial_putc (*s++);
+ }
+}
+
+int getDebugChar (void)
+{
+ unsigned char status = 0;
+
+ while (1) {
+ status = in8 (ACTING_UART1_BASE + UART_LSR);
+ if ((status & asyncLSRDataReady1) != 0x0) {
+ break;
+ }
+ if ((status & ( asyncLSRFramingError1 |
+ asyncLSROverrunError1 |
+ asyncLSRParityError1 |
+ asyncLSRBreakInterrupt1 )) != 0) {
+ out8 (ACTING_UART1_BASE + UART_LSR,
+ asyncLSRFramingError1 |
+ asyncLSROverrunError1 |
+ asyncLSRParityError1 |
+ asyncLSRBreakInterrupt1);
+ }
+ }
+ return (0x000000ff & (int) in8 (ACTING_UART1_BASE));
+}
+
+void kgdb_interruptible (int yes)
+{
+ return;
+}
+
+#else /* ! (CONFIG_KGDB_SER_INDEX & 2) */
+
+void kgdb_serial_init (void)
+{
+ serial_printf ("[on serial] ");
+}
+
+void putDebugChar (int c)
+{
+ serial_putc (c);
+}
+
+void putDebugStr (const char *str)
+{
+ serial_puts (str);
+}
+
+int getDebugChar (void)
+{
+ return serial_getc ();
+}
+
+void kgdb_interruptible (int yes)
+{
+ return;
+}
+#endif /* (CONFIG_KGDB_SER_INDEX & 2) */
+#endif
+
#endif /* defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) ||
defined(CONFIG_S3C2440) || defined (CONFIG_S3C2442) ||
defined (CONFIG_TRAB) */
diff -r -u u-boot/cpu/arm920t/start.S u-boot-UniPd-denx.de/cpu/arm920t/start.S
--- u-boot/cpu/arm920t/start.S 2008-01-21 11:27:32.000000000 +0100
+++ u-boot-UniPd-denx.de/cpu/arm920t/start.S 2009-05-05
19:15:15.000000000 +0200
@@ -780,7 +780,7 @@
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
add r7, sp, #S_PC
- stmdb r7, {sp, lr}^ @ Calling SP, LR
+ stmdb r7, {sp, lr}^ @ NOTE: Save USER SP and LR
str lr, [r7, #0] @ Save calling PC
mrs r6, spsr
str r6, [r7, #4] @ Save CPSR
@@ -788,6 +788,56 @@
mov r0, sp
.endm
+#if defined (CONFIG_CMD_KGDB)
+ /*
+ * U-BOOT runs in SVC32 mode and so is not simple to access SVC's sp and
+ * lr registers, there isn't an appropriate instruction like in ARM11.
+ * kgdb needs the exact content of this registers to work.
+ * ARM9 guarantee access to USR32 mode registers from any other mode but
+ * there is no direct way to access SVC, UND, etc.. registers from other
+ * privileged modes.
+ * This solution work well with SVC <-> UND doesn't work with USR <-> UND
+ * because writing mode bits is a privileged action and can't return.
+ */
+ .macro und_save_regs
+ sub sp, sp, #S_FRAME_SIZE
+ stmia sp, {r0 - r12} @ Calling r0-r12
+ add r7, sp, #S_PC
+ str lr, [r7, #0] @ Save calling PC
+ mrs r6, spsr
+ str r6, [r7, #4] @ Save CPSR
+ str r0, [r7, #8] @ Save OLD_R0
+
+ mrs r0, cpsr @ move cpsr in r0
+ msr cpsr_c, r6 @ move in the previous mode and save sp and lr in
+ mov r1, sp @ r1 and
+ mov r2, lr @ r2 then
+ msr cpsr_c, r0 @ return in the correct mode and
+
+ stmdb r7, {r1, r2} @ save registers on the stack
+ mov r0, sp
+ .endm
+
+ .macro und_restore_regs
+ add r7, sp, #S_PC @ set r7 to point program counter
+ ldr r6, [r7, #4] @ load spsr in r6
+ ldmdb r7, {r1, r2} @ load sp in r1 and lr in r2
+
+ mrs r0, cpsr @ move cpsr in r0
+ msr cpsr_c, r6 @ move in the previous mode and restore r1 and r2 in
+ mov sp, r1 @ sp and
+ mov lr, r2 @ lr then
+ msr cpsr_c, r0 @ return in the correct mode and
+
+ ldmia sp, {r0 - r12} @ Calling r0 - lr
+ mov r0, r0
+ ldr lr, [sp, #S_PC] @ Get PC
+ add sp, sp, #S_FRAME_SIZE
+ movs pc, lr @ return & move spsr_svc into cpsr
+ .endm
+
+#endif /* CONFIG_CMD_KGDB */
+
.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
@@ -823,12 +873,24 @@
/*
* exception handlers
*/
+
+#if defined(CONFIG_CMD_KGDB)
+ .align 5
+undefined_instruction:
+ get_irq_stack
+ und_save_regs
+ bl do_undefined_instruction
+ und_restore_regs
+
+#else /* CONFIG_CMD_KGDB */
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
+#endif /* CONFIG_CMD_KGDB */
+
.align 5
software_interrupt:
get_bad_stack
@@ -854,7 +916,6 @@
bl do_not_used
#ifdef CONFIG_USE_IRQ
-
.align 5
irq:
get_irq_stack
@@ -871,7 +932,6 @@
irq_restore_user_regs
#else
-
.align 5
irq:
get_bad_stack
diff -r -u u-boot/include/_exports.h u-boot-UniPd-denx.de/include/_exports.h
--- u-boot/include/_exports.h 2007-11-06 18:07:07.000000000 +0100
+++ u-boot-UniPd-denx.de/include/_exports.h 2009-05-05
19:19:56.000000000 +0200
@@ -24,3 +24,6 @@
EXPORT_FUNC(i2c_write)
EXPORT_FUNC(i2c_read)
#endif
+#ifdef CONFIG_CMD_KGDB
+EXPORT_FUNC(kgdb_breakpoint)
+#endif
diff -r -u u-boot/include/exports.h u-boot-UniPd-denx.de/include/exports.h
--- u-boot/include/exports.h 2007-11-06 18:07:07.000000000 +0100
+++ u-boot-UniPd-denx.de/include/exports.h 2009-05-05 19:17:07.000000000 +0200
@@ -25,6 +25,9 @@
void setenv (char *varname, char *varvalue);
long simple_strtol(const char *cp,char **endp,unsigned int base);
int strcmp(const char * cs,const char * ct);
+#ifdef CONFIG_CMD_KGDB
+void kgdb_breakpoint(int argc, char *argv[]);
+#endif
#ifdef CONFIG_HAS_UID
void forceenv (char *varname, char *varvalue);
#endif
@@ -45,7 +48,7 @@
XF_MAX
};
-#define XF_VERSION 4
+#define XF_VERSION 5
#if defined(CONFIG_I386)
extern gd_t *global_data;
diff -r -u u-boot/lib_arm/Makefile u-boot-UniPd-denx.de/lib_arm/Makefile
--- u-boot/lib_arm/Makefile 2007-11-06 18:07:08.000000000 +0100
+++ u-boot-UniPd-denx.de/lib_arm/Makefile 2009-01-15 13:03:04.000000000 +0100
@@ -28,7 +28,7 @@
SOBJS = _ashldi3.o _ashrdi3.o _divsi3.o _modsi3.o _udivsi3.o _umodsi3.o
COBJS = armlinux.o board.o \
- cache.o div0.o
+ cache.o div0.o kgdb.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff -r -u u-boot/lib_arm/board.c u-boot-UniPd-denx.de/lib_arm/board.c
--- u-boot/lib_arm/board.c 2007-11-06 18:07:08.000000000 +0100
+++ u-boot-UniPd-denx.de/lib_arm/board.c 2009-05-05 19:18:01.000000000 +0200
@@ -345,6 +345,11 @@
serial_initialize();
#endif
+#if defined(CONFIG_CMD_KGDB)
+ puts ("KGDB: ");
+ kgdb_init ();
+#endif
+
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
----------------------------------------------------------------
This message was sent using IMP, the Internet Messaging Program.
More information about the U-Boot
mailing list