[PATCH,RFC 2.6.14 09/15] KGDB: SuperH-specific changes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This adds basic support for KGDB on SuperH as well as adding some architecture
specific notes to the DocBook file and converting the 7751 to use this.  I
have tested all combinations of 8250 and SCI(F) ports being used as KGDB and
console that I could (one of each usable to me).

 Documentation/DocBook/kgdb.tmpl |   16 
 arch/sh/Kconfig.debug           |   92 --
 arch/sh/Makefile                |    1 
 arch/sh/boards/se/7751/setup.c  |  139 ---
 arch/sh/kernel/Makefile         |    2 
 arch/sh/kernel/cpu/sh3/ex.S     |    2 
 arch/sh/kernel/cpu/sh4/ex.S     |    2 
 arch/sh/kernel/entry.S          |   30 
 arch/sh/kernel/kgdb-jmp.S       |   32 
 arch/sh/kernel/kgdb.c           |  363 +++++++++
 arch/sh/kernel/kgdb_jmp.S       |   33 
 arch/sh/kernel/kgdb_stub.c      | 1491 ----------------------------------------
 arch/sh/kernel/setup.c          |   94 --
 arch/sh/kernel/time.c           |   11 
 arch/sh/kernel/traps.c          |   20 
 arch/sh/mm/extable.c            |    7 
 arch/sh/mm/fault-nommu.c        |   14 
 arch/sh/mm/fault.c              |   12 
 drivers/serial/sh-sci.c         |  298 ++++---
 include/asm-sh/kgdb.h           |  116 ---
 include/asm-sh/system.h         |   40 +
 lib/Kconfig.debug               |    6 
 22 files changed, 676 insertions(+), 2145 deletions(-)

Index: linux-2.6.14/arch/sh/boards/se/7751/setup.c
===================================================================
--- linux-2.6.14.orig/arch/sh/boards/se/7751/setup.c
+++ linux-2.6.14/arch/sh/boards/se/7751/setup.c
@@ -18,10 +18,6 @@
 #include <asm/io.h>
 #include <asm/se7751/se7751.h>
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#endif
-
 /*
  * Configure the Super I/O chip
  */
@@ -83,12 +79,6 @@ const char *get_system_type(void)
 	return "7751 SolutionEngine";
 }
 
-#ifdef CONFIG_SH_KGDB
-static int kgdb_uart_setup(void);
-static struct kgdb_sermap kgdb_uart_sermap = 
-{ "ttyS", 0, kgdb_uart_setup, NULL };
-#endif
- 
 /*
  * Initialize the board
  */
@@ -96,133 +86,4 @@ void __init platform_setup(void)
 {
 	/* Call init_smsc() replacement to set up SuperIO. */
 	/* XXX: RTC setting comes here */
-#ifdef CONFIG_SH_KGDB
-	kgdb_register_sermap(&kgdb_uart_sermap);
-#endif
-}
-
-/*********************************************************************
- * Currently a hack (e.g. does not interact well w/serial.c, lots of *
- * hardcoded stuff) but may be useful if SCI/F needs debugging.      *
- * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and  *
- * arch/i386/lib/kgdb_serial.c).                                     *
- *********************************************************************/
-
-#ifdef CONFIG_SH_KGDB
-#include <linux/types.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-
-#define COM1_PORT 0x3f8  /* Base I/O address */
-#define COM1_IRQ  4      /* IRQ not used yet */
-#define COM2_PORT 0x2f8  /* Base I/O address */
-#define COM2_IRQ  3      /* IRQ not used yet */
-
-#define SB_CLOCK 1843200 /* Serial baud clock */
-#define SB_BASE (SB_CLOCK/16)
-#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
-
-struct uart_port {
-	int base;
-};
-#define UART_NPORTS 2
-struct uart_port uart_ports[] = {
-	{ COM1_PORT },
-	{ COM2_PORT },
-};
-struct uart_port *kgdb_uart_port;
-
-#define UART_IN(reg)	inb_p(kgdb_uart_port->base + reg)
-#define UART_OUT(reg,v)	outb_p((v), kgdb_uart_port->base + reg)
-
-/* Basic read/write functions for the UART */
-#define UART_LSR_RXCERR    (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE)
-static int kgdb_uart_getchar(void)
-{
-	int lsr;
-	int c = -1;
-
-	while (c == -1) {
-		lsr = UART_IN(UART_LSR);
-		if (lsr & UART_LSR_DR) 
-			c = UART_IN(UART_RX);
-		if ((lsr & UART_LSR_RXCERR))
-			c = -1;
-	}
-	return c;
-}
-
-static void kgdb_uart_putchar(int c)
-{
-	while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0)
-		;
-	UART_OUT(UART_TX, c);
-}
-
-/*
- * Initialize UART to configured/requested values.
- * (But we don't interrupts yet, or interact w/serial.c)
- */
-static int kgdb_uart_setup(void)
-{
-	int port;
-	int lcr = 0;
-	int bdiv = 0;
-
-	if (kgdb_portnum >= UART_NPORTS) {
-		KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum);
-		return -1;
-	}
-
-	kgdb_uart_port = &uart_ports[kgdb_portnum];
-
-	/* Init sequence from gdb_hook_interrupt */
-	UART_IN(UART_RX);
-	UART_OUT(UART_IER, 0);
-
-	UART_IN(UART_RX);	/* Serial driver comments say */
-	UART_IN(UART_IIR);	/* this clears interrupt regs */
-	UART_IN(UART_MSR);
-
-	/* Figure basic LCR values */
-	switch (kgdb_bits) {
-	case '7':
-		lcr |= UART_LCR_WLEN7;
-		break;
-	default: case '8': 
-		lcr |= UART_LCR_WLEN8;
-		break;
-	}
-	switch (kgdb_parity) {
-	case 'O':
-		lcr |= UART_LCR_PARITY;
-		break;
-	case 'E':
-		lcr |= (UART_LCR_PARITY | UART_LCR_EPAR);
-		break;
-	default: break;
-	}
-
-	/* Figure the baud rate divisor */
-	bdiv = (SB_BASE/kgdb_baud);
-	
-	/* Set the baud rate and LCR values */
-	UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB));
-	UART_OUT(UART_DLL, (bdiv & 0xff));
-	UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff));
-	UART_OUT(UART_LCR, lcr);
-
-	/* Set the MCR */
-	UART_OUT(UART_MCR, SB_MCR);
-
-	/* Turn off FIFOs for now */
-	UART_OUT(UART_FCR, 0);
-
-	/* Setup complete: initialize function pointers */
-	kgdb_getchar = kgdb_uart_getchar;
-	kgdb_putchar = kgdb_uart_putchar;
-
-	return 0;
 }
-#endif /* CONFIG_SH_KGDB */
Index: linux-2.6.14/arch/sh/Kconfig.debug
===================================================================
--- linux-2.6.14.orig/arch/sh/Kconfig.debug
+++ linux-2.6.14/arch/sh/Kconfig.debug
@@ -29,96 +29,4 @@ config EARLY_PRINTK
 	  This option is only useful porting the kernel to a new machine,
 	  when the kernel may crash or hang before the serial console is
 	  initialised. If unsure, say N.
-
-config KGDB
-	bool "Include KGDB kernel debugger"
-	help
-	  Include in-kernel hooks for kgdb, the Linux kernel source level
-	  debugger.  See <http://kgdb.sourceforge.net/> for more information.
-	  Unless you are intending to debug the kernel, say N here.
-
-menu "KGDB configuration options"
-	depends on KGDB
-
-config MORE_COMPILE_OPTIONS
-	bool "Add any additional compile options"
-	help
-	  If you want to add additional CFLAGS to the kernel build, enable this
-	  option and then enter what you would like to add in the next question.
-	  Note however that -g is already appended with the selection of KGDB.
-
-config COMPILE_OPTIONS
-	string "Additional compile arguments"
-	depends on MORE_COMPILE_OPTIONS
-
-config KGDB_NMI
-	bool "Enter KGDB on NMI"
-	default n
-
-config KGDB_THREAD
-	bool "Include KGDB thread support"
-	default y
-
-config SH_KGDB_CONSOLE
-	bool "Console messages through GDB"
-	default n
-
-config KGDB_SYSRQ
-	bool "Allow SysRq 'G' to enter KGDB"
-	default y
-
-config KGDB_KERNEL_ASSERTS
-	bool "Include KGDB kernel assertions"
-	default n
-
-comment "Serial port setup"
-
-config KGDB_DEFPORT
-	int "Port number (ttySCn)"
-	default "1"
-
-config KGDB_DEFBAUD
-	int "Baud rate"
-	default "115200"
-
-choice
-	prompt "Parity"
-	depends on KGDB
-	default KGDB_DEFPARITY_N
-
-config KGDB_DEFPARITY_N
-	bool "None"
-
-config KGDB_DEFPARITY_E
-	bool "Even"
-
-config KGDB_DEFPARITY_O
-	bool "Odd"
-
-endchoice
-
-choice
-	prompt "Data bits"
-	depends on KGDB
-	default KGDB_DEFBITS_8
-
-config KGDB_DEFBITS_8
-	bool "8"
-
-config KGDB_DEFBITS_7
-	bool "7"
-
-endchoice
-
-endmenu
-
-config FRAME_POINTER
-	bool "Compile the kernel with frame pointers"
-	default y if KGDB
-	help
-	  If you say Y here the resulting kernel image will be slightly larger
-	  and slower, but it will give very useful debugging information.
-	  If you don't debug the kernel, you can say N, but we may not be able
-	  to solve problems without frame pointers.
-
 endmenu
Index: linux-2.6.14/arch/sh/kernel/cpu/sh3/ex.S
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/cpu/sh3/ex.S
+++ linux-2.6.14/arch/sh/kernel/cpu/sh3/ex.S
@@ -43,7 +43,7 @@ ENTRY(exception_handling_table)
 	.long	exception_error	! reserved_instruction (filled by trap_init) /* 180 */
 	.long	exception_error	! illegal_slot_instruction (filled by trap_init) /*1A0*/
 ENTRY(nmi_slot)
-#if defined (CONFIG_KGDB_NMI)
+#if defined (CONFIG_KGDB)
 	.long	debug_enter	/* 1C0 */	! Allow trap to debugger
 #else
 	.long	exception_none	/* 1C0 */	! Not implemented yet
Index: linux-2.6.14/arch/sh/kernel/cpu/sh4/ex.S
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/cpu/sh4/ex.S
+++ linux-2.6.14/arch/sh/kernel/cpu/sh4/ex.S
@@ -47,7 +47,7 @@ ENTRY(exception_handling_table)
 	.long	exception_error	! reserved_instruction (filled by trap_init) /* 180 */
 	.long	exception_error	! illegal_slot_instruction (filled by trap_init) /*1A0*/
 ENTRY(nmi_slot)
-#if defined (CONFIG_KGDB_NMI)
+#if defined (CONFIG_KGDB)
 	.long	debug_enter	/* 1C0 */	! Allow trap to debugger
 #else
 	.long	exception_none	/* 1C0 */	! Not implemented yet
Index: linux-2.6.14/arch/sh/kernel/entry.S
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/entry.S
+++ linux-2.6.14/arch/sh/kernel/entry.S
@@ -92,7 +92,7 @@ INTEVT  = 0xff000028
 MMU_TEA = 0xff00000c		! TLB Exception Address Register
 #endif
 
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
 NMI_VEC = 0x1c0			! Must catch early for debounce
 #endif
 
@@ -244,31 +244,33 @@ call_dae:
 2:	.long   do_address_error
 #endif /* CONFIG_MMU */
 
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB)
 ! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present.
 ! If both are configured, handle the debug traps (breakpoints) in SW,
 ! but still allow BIOS traps to FW.
 
 	.align	2
 debug_kernel:
-#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB)
+#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_KGDB)
 	/* Force BIOS call to FW (debug_trap put TRA in r8) */
 	mov	r8,r0
 	shlr2	r0
 	cmp/eq	#0x3f,r0
 	bt	debug_kernel_fw
-#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */
+#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_KGDB */
 
-debug_enter:		
-#if defined(CONFIG_SH_KGDB)
+	.align 2
+	.globl debug_enter
+debug_enter:
+#if defined(CONFIG_KGDB)
 	/* Jump to kgdb, pass stacked regs as arg */
 debug_kernel_sw:
 	mov.l	3f, r0
 	jmp	@r0
 	 mov	r15, r4
 	.align	2
-3:	.long	kgdb_handle_exception
-#endif /* CONFIG_SH_KGDB */
+3:	.long	kgdb_exception_handler
+#endif /* CONFIG_KGDB */
 
 #if defined(CONFIG_SH_STANDARD_BIOS)
 	/* Unwind the stack and jmp to the debug entry */
@@ -310,12 +312,12 @@ debug_kernel_fw:
 2:	.long	gdb_vbr_vector
 #endif /* CONFIG_SH_STANDARD_BIOS */
 
-#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_KGDB */
 
 
 	.align	2
-debug_trap:	
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+debug_trap:
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB)
 	mov	#OFF_SR, r0
 	mov.l	@(r0,r15), r0		! get status register
 	shll	r0
@@ -659,7 +661,7 @@ skip_restore:
 6:	or	k0, k2			! Set the IMASK-bits
 	ldc	k2, ssr
 	!
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
 	! Clear in_nmi
 	mov.l	4f, k0
 	mov	#0, k1
@@ -711,7 +713,7 @@ tlb_miss:
 interrupt:
 	mov.l	2f, k2
 	mov.l	3f, k3
-#if defined(CONFIG_KGDB_NMI)
+#if defined(CONFIG_KGDB)
 	! Debounce (filter nested NMI)
 	mov.l	@k2, k0
 	mov.l	5f, k1
@@ -726,7 +728,7 @@ interrupt:
 5:	.long	NMI_VEC
 6:	.long	in_nmi
 0:
-#endif /* defined(CONFIG_KGDB_NMI) */
+#endif /* defined(CONFIG_KGDB) */
 	bra	handle_exception
 	 mov.l	@k2, k2
 
Index: linux-2.6.14/arch/sh/kernel/kgdb.c
===================================================================
--- /dev/null
+++ linux-2.6.14/arch/sh/kernel/kgdb.c
@@ -0,0 +1,363 @@
+/*
+ * arch/sh/kernel/kgdb.c
+ *
+ * Contains SH-specific low-level support for KGDB.
+ *
+ * Containes extracts from code by Glenn Engel, Jim Kingdon,
+ * David Grothe <[email protected]>, Tigran Aivazian <[email protected]>,
+ * Amit S. Kale <[email protected]>,  William Gatliff <[email protected]>,
+ * Ben Lee, Steve Chamberlain and Benoit Miller <[email protected]>,
+ * Henry Bell <[email protected]> and Jeremy Siegel <[email protected]>
+ *
+ * Maintainer: Tom Rini <[email protected]>
+ *
+ * 2004 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+
+#include <asm/system.h>
+#include <asm/current.h>
+#include <asm/signal.h>
+#include <asm/pgtable.h>
+#include <asm/ptrace.h>
+
+extern void per_cpu_trap_init(void);
+extern atomic_t cpu_doing_single_step;
+
+/* Function pointers for linkage */
+static struct kgdb_regs trap_registers;
+
+/* Globals. */
+char in_nmi;			/* Set during NMI to prevent reentry */
+
+/* TRA differs sh3/4 */
+#if defined(CONFIG_CPU_SH3)
+#define TRA 0xffffffd0
+#elif defined(CONFIG_CPU_SH4)
+#define TRA 0xff000020
+#endif
+
+/* Macros for single step instruction identification */
+#define OPCODE_BT(op)         (((op) & 0xff00) == 0x8900)
+#define OPCODE_BF(op)         (((op) & 0xff00) == 0x8b00)
+#define OPCODE_BTF_DISP(op)   (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \
+			      (((op) & 0x7f ) << 1))
+#define OPCODE_BFS(op)        (((op) & 0xff00) == 0x8f00)
+#define OPCODE_BTS(op)        (((op) & 0xff00) == 0x8d00)
+#define OPCODE_BRA(op)        (((op) & 0xf000) == 0xa000)
+#define OPCODE_BRA_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
+			      (((op) & 0x7ff) << 1))
+#define OPCODE_BRAF(op)       (((op) & 0xf0ff) == 0x0023)
+#define OPCODE_BRAF_REG(op)   (((op) & 0x0f00) >> 8)
+#define OPCODE_BSR(op)        (((op) & 0xf000) == 0xb000)
+#define OPCODE_BSR_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
+			      (((op) & 0x7ff) << 1))
+#define OPCODE_BSRF(op)       (((op) & 0xf0ff) == 0x0003)
+#define OPCODE_BSRF_REG(op)   (((op) >> 8) & 0xf)
+#define OPCODE_JMP(op)        (((op) & 0xf0ff) == 0x402b)
+#define OPCODE_JMP_REG(op)    (((op) >> 8) & 0xf)
+#define OPCODE_JSR(op)        (((op) & 0xf0ff) == 0x400b)
+#define OPCODE_JSR_REG(op)    (((op) >> 8) & 0xf)
+#define OPCODE_RTS(op)        ((op) == 0xb)
+#define OPCODE_RTE(op)        ((op) == 0x2b)
+
+#define SR_T_BIT_MASK           0x1
+#define STEP_OPCODE             0xc320
+#define BIOS_CALL_TRAP          0x3f
+
+/* Exception codes as per SH-4 core manual */
+#define ADDRESS_ERROR_LOAD_VEC   7
+#define ADDRESS_ERROR_STORE_VEC  8
+#define TRAP_VEC                 11
+#define INVALID_INSN_VEC         12
+#define INVALID_SLOT_VEC         13
+#define NMI_VEC                  14
+#define SERIAL_BREAK_VEC         58
+
+/* Misc static */
+static int stepped_address;
+static short stepped_opcode;
+
+/* Translate SH-3/4 exception numbers to unix-like signal values */
+static int compute_signal(const int excep_code)
+{
+	switch (excep_code) {
+	case INVALID_INSN_VEC:
+	case INVALID_SLOT_VEC:
+		return SIGILL;
+	case ADDRESS_ERROR_LOAD_VEC:
+	case ADDRESS_ERROR_STORE_VEC:
+		return SIGSEGV;
+	case SERIAL_BREAK_VEC:
+	case NMI_VEC:
+		return SIGINT;
+	default:
+		/* Act like it was a break/trap. */
+		return SIGTRAP;
+	}
+}
+
+/*
+ * Translate the registers of the system into the format that GDB wants.  Since
+ * we use a local structure to store things, instead of getting them out
+ * of pt_regs, we can just do a memcpy.
+ */
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *ign)
+{
+	memcpy(gdb_regs, &trap_registers, sizeof(trap_registers));
+}
+
+/*
+ * On SH we save: r1 (prev->thread.sp) r2 (prev->thread.pc) r4 (prev) r5 (next)
+ * r6 (next->thread.sp) r7 (next->thread.pc)
+ */
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	int count;
+
+	for (count = 0; count < 16; count++)
+		*(gdb_regs++) = 0;
+	*(gdb_regs++) = p->thread.pc;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+	*(gdb_regs++) = 0;
+}
+
+/*
+ * Translate the registers values that GDB has given us back into the
+ * format of the system.  See the comment above about memcpy.
+ */
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *ign)
+{
+	memcpy(&trap_registers, gdb_regs, sizeof(trap_registers));
+}
+
+/* Calculate the new address for after a step */
+static short *get_step_address(void)
+{
+	short op = *(short *)trap_registers.pc;
+	long addr;
+
+	/* BT */
+	if (OPCODE_BT(op)) {
+		if (trap_registers.sr & SR_T_BIT_MASK)
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 2;
+	}
+
+	/* BTS */
+	else if (OPCODE_BTS(op)) {
+		if (trap_registers.sr & SR_T_BIT_MASK)
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 4;	/* Not in delay slot */
+	}
+
+	/* BF */
+	else if (OPCODE_BF(op)) {
+		if (!(trap_registers.sr & SR_T_BIT_MASK))
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 2;
+	}
+
+	/* BFS */
+	else if (OPCODE_BFS(op)) {
+		if (!(trap_registers.sr & SR_T_BIT_MASK))
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 4;	/* Not in delay slot */
+	}
+
+	/* BRA */
+	else if (OPCODE_BRA(op))
+		addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op);
+
+	/* BRAF */
+	else if (OPCODE_BRAF(op))
+		addr = trap_registers.pc + 4
+		    + trap_registers.regs[OPCODE_BRAF_REG(op)];
+
+	/* BSR */
+	else if (OPCODE_BSR(op))
+		addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op);
+
+	/* BSRF */
+	else if (OPCODE_BSRF(op))
+		addr = trap_registers.pc + 4
+		    + trap_registers.regs[OPCODE_BSRF_REG(op)];
+
+	/* JMP */
+	else if (OPCODE_JMP(op))
+		addr = trap_registers.regs[OPCODE_JMP_REG(op)];
+
+	/* JSR */
+	else if (OPCODE_JSR(op))
+		addr = trap_registers.regs[OPCODE_JSR_REG(op)];
+
+	/* RTS */
+	else if (OPCODE_RTS(op))
+		addr = trap_registers.pr;
+
+	/* RTE */
+	else if (OPCODE_RTE(op))
+		addr = trap_registers.regs[15];
+
+	/* Other */
+	else
+		addr = trap_registers.pc + 2;
+
+	kgdb_flush_icache_range(addr, addr + 2);
+	return (short *)addr;
+}
+
+/* The command loop, read and act on requests */
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+			       char *remcom_in_buffer, char *remcom_out_buffer,
+			       struct pt_regs *ign)
+{
+	unsigned long addr;
+	char *ptr = &remcom_in_buffer[1];
+
+	/* Examine first char of buffer to see what we need to do */
+	switch (remcom_in_buffer[0]) {
+	case 'c':		/* Continue at address AA..AA (optional) */
+	case 's':		/* Step one instruction from AA..AA */
+		/* Try to read optional parameter, PC unchanged if none */
+		if (kgdb_hex2long(&ptr, &addr))
+			trap_registers.pc = addr;
+
+		atomic_set(&cpu_doing_single_step, -1);
+		if (remcom_in_buffer[0] == 's') {
+			/* Replace the instruction immediately after the
+			 * current instruction (i.e. next in the expected
+			 * flow of control) with a trap instruction, so that
+			 * returning will cause only a single instruction to
+			 * be executed. Note that this model is slightly
+			 * broken for instructions with delay slots
+			 * (e.g. B[TF]S, BSR, BRA etc), where both the branch
+			 * and the instruction in the delay slot will be
+			 * executed.
+			 */
+			/* Determine where the target instruction will send
+			 * us to */
+			unsigned short *next_addr = get_step_address();
+			stepped_address = (int)next_addr;
+
+			/* Replace it */
+			stepped_opcode = *(short *)next_addr;
+			*next_addr = STEP_OPCODE;
+
+			/* Flush and return */
+			kgdb_flush_icache_range((long)next_addr,
+						(long)next_addr + 2);
+			if (kgdb_contthread)
+				atomic_set(&cpu_doing_single_step,
+					   smp_processor_id());
+		}
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * When an exception has occured, we are called.  We need to set things
+ * up so that we can call kgdb_handle_exception to handle requests from
+ * the remote GDB.
+ */
+void kgdb_exception_handler(struct pt_regs *regs)
+{
+	int excep_code, vbr_val;
+	int count;
+
+	/* Copy kernel regs (from stack) */
+	for (count = 0; count < 16; count++)
+		trap_registers.regs[count] = regs->regs[count];
+	trap_registers.pc = regs->pc;
+	trap_registers.pr = regs->pr;
+	trap_registers.sr = regs->sr;
+	trap_registers.gbr = regs->gbr;
+	trap_registers.mach = regs->mach;
+	trap_registers.macl = regs->macl;
+
+	__asm__ __volatile__("stc vbr, %0":"=r"(vbr_val));
+	trap_registers.vbr = vbr_val;
+
+	/* Get the execption code. */
+	__asm__ __volatile__("stc r2_bank, %0":"=r"(excep_code));
+
+	excep_code >>= 5;
+
+	/* If we got an NMI, and KGDB is not yet initialized, call
+	 * breakpoint() to try and initialize everything for us. */
+	if (excep_code == NMI_VEC && !kgdb_initialized) {
+		breakpoint();
+		return;
+	}
+
+	/* TRAP_VEC exception indicates a software trap inserted in place of
+	 * code by GDB so back up PC by one instruction, as this instruction
+	 * will later be replaced by its original one.  Do NOT do this for
+	 * trap 0xff, since that indicates a compiled-in breakpoint which
+	 * will not be replaced (and we would retake the trap forever) */
+	if (excep_code == TRAP_VEC &&
+	    (*(volatile unsigned long *)TRA != (0xff << 2)))
+		trap_registers.pc -= 2;
+
+	/* If we have been single-stepping, put back the old instruction.
+	 * We use stepped_address in case we have stopped more than one
+	 * instruction away. */
+	if (stepped_opcode != 0) {
+		*(short *)stepped_address = stepped_opcode;
+		kgdb_flush_icache_range(stepped_address, stepped_address + 2);
+	}
+	stepped_opcode = 0;
+
+	/* Call the stub to do the processing.  Note that not everything we
+	 * need to send back and forth lives in pt_regs. */
+	kgdb_handle_exception(excep_code, compute_signal(excep_code), 0, regs);
+
+	/* Copy back the (maybe modified) registers */
+	for (count = 0; count < 16; count++)
+		regs->regs[count] = trap_registers.regs[count];
+	regs->pc = trap_registers.pc;
+	regs->pr = trap_registers.pr;
+	regs->sr = trap_registers.sr;
+	regs->gbr = trap_registers.gbr;
+	regs->mach = trap_registers.mach;
+	regs->macl = trap_registers.macl;
+
+	vbr_val = trap_registers.vbr;
+	__asm__ __volatile__("ldc %0, vbr": :"r"(vbr_val));
+}
+
+int __init kgdb_arch_init(void)
+{
+	per_cpu_trap_init();
+
+	return 0;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+	.gdb_bpt_instr = {0xff, 0xc3},
+#else
+	.gdb_bpt_instr = {0xc3, 0xff},
+#endif
+};
Index: linux-2.6.14/arch/sh/kernel/kgdb_jmp.S
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/kgdb_jmp.S
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <linux/linkage.h>
-
-ENTRY(setjmp)
-	add	#(9*4), r4
-	sts.l	pr, @-r4
-	mov.l	r15, @-r4
-	mov.l	r14, @-r4
-	mov.l	r13, @-r4
-	mov.l	r12, @-r4
-	mov.l	r11, @-r4
-	mov.l	r10, @-r4
-	mov.l	r9, @-r4
-	mov.l	r8, @-r4
-	rts
-	 mov	#0, r0
-
-ENTRY(longjmp)
-	mov.l	@r4+, r8
-	mov.l	@r4+, r9
-	mov.l	@r4+, r10
-	mov.l	@r4+, r11
-	mov.l	@r4+, r12
-	mov.l	@r4+, r13
-	mov.l	@r4+, r14
-	mov.l	@r4+, r15
-	lds.l	@r4+, pr
-	mov	r5, r0
-	tst	r0, r0
-	bf	1f
-	mov	#1, r0	! in case val==0
-1:	rts
-	 nop
-
Index: linux-2.6.14/arch/sh/kernel/kgdb-jmp.S
===================================================================
--- /dev/null
+++ linux-2.6.14/arch/sh/kernel/kgdb-jmp.S
@@ -0,0 +1,32 @@
+#include <linux/linkage.h>
+
+ENTRY(kgdb_fault_setjmp)
+	add	#(9*4), r4
+	sts.l	pr, @-r4
+	mov.l	r15, @-r4
+	mov.l	r14, @-r4
+	mov.l	r13, @-r4
+	mov.l	r12, @-r4
+	mov.l	r11, @-r4
+	mov.l	r10, @-r4
+	mov.l	r9, @-r4
+	mov.l	r8, @-r4
+	rts
+	 mov	#0, r0
+
+ENTRY(kgdb_fault_longjmp)
+	mov.l	@r4+, r8
+	mov.l	@r4+, r9
+	mov.l	@r4+, r10
+	mov.l	@r4+, r11
+	mov.l	@r4+, r12
+	mov.l	@r4+, r13
+	mov.l	@r4+, r14
+	mov.l	@r4+, r15
+	lds.l	@r4+, pr
+	mov	r5, r0
+	tst	r0, r0
+	bf	1f
+	mov	#1, r0
+1:	rts
+	 nop
Index: linux-2.6.14/arch/sh/kernel/kgdb_stub.c
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/kgdb_stub.c
+++ /dev/null
@@ -1,1491 +0,0 @@
-/*
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * Containes extracts from code by Glenn Engel, Jim Kingdon,
- * David Grothe <[email protected]>, Tigran Aivazian <[email protected]>,
- * Amit S. Kale <[email protected]>,  William Gatliff <[email protected]>,
- * Ben Lee, Steve Chamberlain and Benoit Miller <[email protected]>.
- * 
- * This version by Henry Bell <[email protected]>
- * Minor modifications by Jeremy Siegel <[email protected]>
- * 
- * Contains low-level support for remote debug using GDB. 
- *
- * To enable debugger support, two things need to happen. A call to
- * set_debug_traps() is necessary in order to allow any breakpoints
- * or error conditions to be properly intercepted and reported to gdb.
- * A breakpoint also needs to be generated to begin communication.  This
- * is most easily accomplished by a call to breakpoint() which does
- * a trapa if the initialisation phase has been successfully completed.
- *
- * In this case, set_debug_traps() is not used to "take over" exceptions;
- * other kernel code is modified instead to enter the kgdb functions here
- * when appropriate (see entry.S for breakpoint traps and NMI interrupts,
- * see traps.c for kernel error exceptions).
- *
- * The following gdb commands are supported:
- *
- *    Command       Function                               Return value
- *
- *    g             return the value of the CPU registers  hex data or ENN
- *    G             set the value of the CPU registers     OK or ENN
- *
- *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
- *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
- *    XAA..AA,LLLL: Same, but data is binary (not hex)     OK or ENN
- *
- *    c             Resume at current address              SNN   ( signal NN)
- *    cAA..AA       Continue at address AA..AA             SNN
- *    CNN;          Resume at current address with signal  SNN
- *    CNN;AA..AA    Resume at address AA..AA with signal   SNN
- *
- *    s             Step one instruction                   SNN
- *    sAA..AA       Step one instruction from AA..AA       SNN
- *    SNN;          Step one instruction with signal       SNN
- *    SNNAA..AA     Step one instruction from AA..AA w/NN  SNN
- *
- *    k             kill (Detach GDB)
- *
- *    d             Toggle debug flag
- *    D             Detach GDB 
- *
- *    Hct           Set thread t for operations,           OK or ENN
- *                  c = 'c' (step, cont), c = 'g' (other
- *                  operations)
- *
- *    qC            Query current thread ID                QCpid
- *    qfThreadInfo  Get list of current threads (first)    m<id>
- *    qsThreadInfo   "    "  "     "      "   (subsequent)
- *    qOffsets      Get section offsets                  Text=x;Data=y;Bss=z
- * 
- *    TXX           Find if thread XX is alive             OK or ENN
- *    ?             What was the last sigval ?             SNN   (signal NN)
- *    O             Output to GDB console
- *
- * Remote communication protocol.
- *
- *    A debug packet whose contents are <data> is encapsulated for
- *    transmission in the form:
- *
- *       $ <data> # CSUM1 CSUM2
- *
- *       <data> must be ASCII alphanumeric and cannot include characters
- *       '$' or '#'.  If <data> starts with two characters followed by
- *       ':', then the existing stubs interpret this as a sequence number.
- *
- *       CSUM1 and CSUM2 are ascii hex representation of an 8-bit 
- *       checksum of <data>, the most significant nibble is sent first.
- *       the hex digits 0-9,a-f are used.
- *
- *    Receiver responds with:
- *
- *       +       - if CSUM is correct and ready for next packet
- *       -       - if CSUM is incorrect
- *
- * Responses can be run-length encoded to save space.  A '*' means that
- * the next character is an ASCII encoding giving a repeat count which
- * stands for that many repititions of the character preceding the '*'.
- * The encoding is n+29, yielding a printable character where n >=3 
- * (which is where RLE starts to win).  Don't use an n > 126. 
- *
- * So "0* " means the same as "0000".
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/current.h>
-#include <asm/signal.h>
-#include <asm/pgtable.h>
-#include <asm/ptrace.h>
-#include <asm/kgdb.h>
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
-#include <linux/console.h>
-#endif
-
-/* Function pointers for linkage */
-kgdb_debug_hook_t *kgdb_debug_hook;
-kgdb_bus_error_hook_t *kgdb_bus_err_hook;
-
-int (*kgdb_getchar)(void);
-void (*kgdb_putchar)(int);
-
-static void put_debug_char(int c)
-{
-	if (!kgdb_putchar)
-		return;
-	(*kgdb_putchar)(c);
-}
-static int get_debug_char(void)
-{
-	if (!kgdb_getchar)
-		return -1;
-	return (*kgdb_getchar)();
-}
-
-/* Num chars in in/out bound buffers, register packets need NUMREGBYTES * 2 */
-#define BUFMAX 1024
-#define NUMREGBYTES (MAXREG*4)
-#define OUTBUFMAX (NUMREGBYTES*2+512)
-
-enum regs {
-	R0 = 0, R1,  R2,  R3,   R4,   R5,  R6, R7,
-	R8, R9, R10, R11, R12,  R13,  R14, R15,
-	PC, PR, GBR, VBR, MACH, MACL, SR,
-	/*  */
-	MAXREG
-};
-
-static unsigned int registers[MAXREG];
-struct kgdb_regs trap_registers;
-
-char kgdb_in_gdb_mode;
-char in_nmi;			/* Set during NMI to prevent reentry */
-int kgdb_nofault;		/* Boolean to ignore bus errs (i.e. in GDB) */
-int kgdb_enabled = 1;		/* Default to enabled, cmdline can disable */
-int kgdb_halt;
-
-/* Exposed for user access */
-struct task_struct *kgdb_current;
-unsigned int kgdb_g_imask;
-int kgdb_trapa_val;
-int kgdb_excode;
-
-/* Default values for SCI (can override via kernel args in setup.c) */
-#ifndef CONFIG_KGDB_DEFPORT
-#define CONFIG_KGDB_DEFPORT 1
-#endif
-
-#ifndef CONFIG_KGDB_DEFBAUD
-#define CONFIG_KGDB_DEFBAUD 115200
-#endif
-
-#if defined(CONFIG_KGDB_DEFPARITY_E)
-#define CONFIG_KGDB_DEFPARITY 'E'
-#elif defined(CONFIG_KGDB_DEFPARITY_O)
-#define CONFIG_KGDB_DEFPARITY 'O'
-#else /* CONFIG_KGDB_DEFPARITY_N */
-#define CONFIG_KGDB_DEFPARITY 'N'
-#endif
-
-#ifdef CONFIG_KGDB_DEFBITS_7
-#define CONFIG_KGDB_DEFBITS '7'
-#else /* CONFIG_KGDB_DEFBITS_8 */
-#define CONFIG_KGDB_DEFBITS '8'
-#endif
-
-/* SCI/UART settings, used in kgdb_console_setup() */
-int  kgdb_portnum = CONFIG_KGDB_DEFPORT;
-int  kgdb_baud = CONFIG_KGDB_DEFBAUD;
-char kgdb_parity = CONFIG_KGDB_DEFPARITY;
-char kgdb_bits = CONFIG_KGDB_DEFBITS;
-
-/* Jump buffer for setjmp/longjmp */
-static jmp_buf rem_com_env;
-
-/* TRA differs sh3/4 */
-#if defined(CONFIG_CPU_SH3)
-#define TRA 0xffffffd0
-#elif defined(CONFIG_CPU_SH4)
-#define TRA 0xff000020
-#endif
-
-/* Macros for single step instruction identification */
-#define OPCODE_BT(op)         (((op) & 0xff00) == 0x8900)
-#define OPCODE_BF(op)         (((op) & 0xff00) == 0x8b00)
-#define OPCODE_BTF_DISP(op)   (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \
-			      (((op) & 0x7f ) << 1))
-#define OPCODE_BFS(op)        (((op) & 0xff00) == 0x8f00)
-#define OPCODE_BTS(op)        (((op) & 0xff00) == 0x8d00)
-#define OPCODE_BRA(op)        (((op) & 0xf000) == 0xa000)
-#define OPCODE_BRA_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
-			      (((op) & 0x7ff) << 1))
-#define OPCODE_BRAF(op)       (((op) & 0xf0ff) == 0x0023)
-#define OPCODE_BRAF_REG(op)   (((op) & 0x0f00) >> 8)
-#define OPCODE_BSR(op)        (((op) & 0xf000) == 0xb000)
-#define OPCODE_BSR_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
-			      (((op) & 0x7ff) << 1))
-#define OPCODE_BSRF(op)       (((op) & 0xf0ff) == 0x0003)
-#define OPCODE_BSRF_REG(op)   (((op) >> 8) & 0xf)
-#define OPCODE_JMP(op)        (((op) & 0xf0ff) == 0x402b)
-#define OPCODE_JMP_REG(op)    (((op) >> 8) & 0xf)
-#define OPCODE_JSR(op)        (((op) & 0xf0ff) == 0x400b)
-#define OPCODE_JSR_REG(op)    (((op) >> 8) & 0xf)
-#define OPCODE_RTS(op)        ((op) == 0xb)
-#define OPCODE_RTE(op)        ((op) == 0x2b)
-
-#define SR_T_BIT_MASK           0x1
-#define STEP_OPCODE             0xc320
-#define BIOS_CALL_TRAP          0x3f
-
-/* Exception codes as per SH-4 core manual */
-#define ADDRESS_ERROR_LOAD_VEC   7
-#define ADDRESS_ERROR_STORE_VEC  8
-#define TRAP_VEC                 11
-#define INVALID_INSN_VEC         12
-#define INVALID_SLOT_VEC         13
-#define NMI_VEC                  14
-#define USER_BREAK_VEC           15
-#define SERIAL_BREAK_VEC         58
-
-/* Misc static */
-static int stepped_address;
-static short stepped_opcode;
-static const char hexchars[] = "0123456789abcdef";
-static char in_buffer[BUFMAX];
-static char out_buffer[OUTBUFMAX];
-
-static void kgdb_to_gdb(const char *s);
-
-#ifdef CONFIG_KGDB_THREAD
-static struct task_struct *trapped_thread;
-static struct task_struct *current_thread;
-typedef unsigned char threadref[8];
-#define BUF_THREAD_ID_SIZE 16
-#endif
-
-/* Return addr as a real volatile address */
-static inline unsigned int ctrl_inl(const unsigned long addr)
-{
-	return *(volatile unsigned long *) addr;
-}
-
-/* Correctly set *addr using volatile */
-static inline void ctrl_outl(const unsigned int b, unsigned long addr)
-{
-	*(volatile unsigned long *) addr = b;
-}
-
-/* Get high hex bits */
-static char highhex(const int x)
-{
-	return hexchars[(x >> 4) & 0xf];
-}
-
-/* Get low hex bits */
-static char lowhex(const int x)
-{
-	return hexchars[x & 0xf];
-}
-
-/* Convert ch to hex */
-static int hex(const char ch)
-{
-	if ((ch >= 'a') && (ch <= 'f'))
-		return (ch - 'a' + 10);
-	if ((ch >= '0') && (ch <= '9'))
-		return (ch - '0');
-	if ((ch >= 'A') && (ch <= 'F'))
-		return (ch - 'A' + 10);
-	return (-1);
-}
-
-/* Convert the memory pointed to by mem into hex, placing result in buf.
-   Returns a pointer to the last char put in buf (null) */
-static char *mem_to_hex(const char *mem, char *buf, const int count)
-{
-	int i;
-	int ch;
-	unsigned short s_val;
-	unsigned long l_val;
-
-	/* Check for 16 or 32 */
-	if (count == 2 && ((long) mem & 1) == 0) {
-		s_val = *(unsigned short *) mem;
-		mem = (char *) &s_val;
-	} else if (count == 4 && ((long) mem & 3) == 0) {
-		l_val = *(unsigned long *) mem;
-		mem = (char *) &l_val;
-	}
-	for (i = 0; i < count; i++) {
-		ch = *mem++;
-		*buf++ = highhex(ch);
-		*buf++ = lowhex(ch);
-	}
-	*buf = 0;
-	return (buf);
-}
-
-/* Convert the hex array pointed to by buf into binary, to be placed in mem.
-   Return a pointer to the character after the last byte written */
-static char *hex_to_mem(const char *buf, char *mem, const int count)
-{
-	int i;
-	unsigned char ch;
-
-	for (i = 0; i < count; i++) {
-		ch = hex(*buf++) << 4;
-		ch = ch + hex(*buf++);
-		*mem++ = ch;
-	}
-	return (mem);
-}
-
-/* While finding valid hex chars, convert to an integer, then return it */
-static int hex_to_int(char **ptr, int *int_value)
-{
-	int num_chars = 0;
-	int hex_value;
-
-	*int_value = 0;
-
-	while (**ptr) {
-		hex_value = hex(**ptr);
-		if (hex_value >= 0) {
-			*int_value = (*int_value << 4) | hex_value;
-			num_chars++;
-		} else
-			break;
-		(*ptr)++;
-	}
-	return num_chars;
-}
-
-/*  Copy the binary array pointed to by buf into mem.  Fix $, #,
-    and 0x7d escaped with 0x7d.  Return a pointer to the character 
-    after the last byte written. */
-static char *ebin_to_mem(const char *buf, char *mem, int count)
-{
-	for (; count > 0; count--, buf++) {
-		if (*buf == 0x7d)
-			*mem++ = *(++buf) ^ 0x20;
-		else
-			*mem++ = *buf;
-	}
-	return mem;
-}
-
-/* Pack a hex byte */
-static char *pack_hex_byte(char *pkt, int byte)
-{
-	*pkt++ = hexchars[(byte >> 4) & 0xf];
-	*pkt++ = hexchars[(byte & 0xf)];
-	return pkt;
-}
-
-#ifdef CONFIG_KGDB_THREAD
-
-/* Pack a thread ID */
-static char *pack_threadid(char *pkt, threadref * id)
-{
-	char *limit;
-	unsigned char *altid;
-
-	altid = (unsigned char *) id;
-
-	limit = pkt + BUF_THREAD_ID_SIZE;
-	while (pkt < limit)
-		pkt = pack_hex_byte(pkt, *altid++);
-	return pkt;
-}
-
-/* Convert an integer into our threadref */
-static void int_to_threadref(threadref * id, const int value)
-{
-	unsigned char *scan = (unsigned char *) id;
-	int i = 4;
-
-	while (i--)
-		*scan++ = 0;
-
-	*scan++ = (value >> 24) & 0xff;
-	*scan++ = (value >> 16) & 0xff;
-	*scan++ = (value >> 8) & 0xff;
-	*scan++ = (value & 0xff);
-}
-
-/* Return a task structure ptr for a particular pid */
-static struct task_struct *get_thread(int pid)
-{
-	struct task_struct *thread;
-
-	/* Use PID_MAX w/gdb for pid 0 */
-	if (pid == PID_MAX) pid = 0;
-
-	/* First check via PID */
-	thread = find_task_by_pid(pid);
-
-	if (thread)
-		return thread;
-
-	/* Start at the start */
-	thread = init_tasks[0];
-
-	/* Walk along the linked list of tasks */
-	do {
-		if (thread->pid == pid)
-			return thread;
-		thread = thread->next_task;
-	} while (thread != init_tasks[0]);
-
-	return NULL;
-}
-
-#endif /* CONFIG_KGDB_THREAD */
-
-/* Scan for the start char '$', read the packet and check the checksum */
-static void get_packet(char *buffer, int buflen)
-{
-	unsigned char checksum;
-	unsigned char xmitcsum;
-	int i;
-	int count;
-	char ch;
-
-	do {
-		/* Ignore everything until the start character */
-		while ((ch = get_debug_char()) != '$');
-
-		checksum = 0;
-		xmitcsum = -1;
-		count = 0;
-
-		/* Now, read until a # or end of buffer is found */
-		while (count < (buflen - 1)) {
-			ch = get_debug_char();
-
-			if (ch == '#')
-				break;
-
-			checksum = checksum + ch;
-			buffer[count] = ch;
-			count = count + 1;
-		}
-
-		buffer[count] = 0;
-
-		/* Continue to read checksum following # */
-		if (ch == '#') {
-			xmitcsum = hex(get_debug_char()) << 4;
-			xmitcsum += hex(get_debug_char());
-
-			/* Checksum */
-			if (checksum != xmitcsum)
-				put_debug_char('-');	/* Failed checksum */
-			else {
-				/* Ack successful transfer */
-				put_debug_char('+');
-
-				/* If a sequence char is present, reply 
-				   the sequence ID */
-				if (buffer[2] == ':') {
-					put_debug_char(buffer[0]);
-					put_debug_char(buffer[1]);
-
-					/* Remove sequence chars from buffer */
-					count = strlen(buffer);
-					for (i = 3; i <= count; i++)
-						buffer[i - 3] = buffer[i];
-				}
-			}
-		}
-	}
-	while (checksum != xmitcsum);	/* Keep trying while we fail */
-}
-
-/* Send the packet in the buffer with run-length encoding */
-static void put_packet(char *buffer)
-{
-	int checksum;
-	char *src;
-	int runlen;
-	int encode;
-
-	do {
-		src = buffer;
-		put_debug_char('$');
-		checksum = 0;
-
-		/* Continue while we still have chars left */
-		while (*src) {
-			/* Check for runs up to 99 chars long */
-			for (runlen = 1; runlen < 99; runlen++) {
-				if (src[0] != src[runlen])
-					break;
-			}
-
-			if (runlen > 3) {
-				/* Got a useful amount, send encoding */
-				encode = runlen + ' ' - 4;
-				put_debug_char(*src);   checksum += *src;
-				put_debug_char('*');    checksum += '*';
-				put_debug_char(encode); checksum += encode;
-				src += runlen;
-			} else {
-				/* Otherwise just send the current char */
-				put_debug_char(*src);   checksum += *src;
-				src += 1;
-			}
-		}
-
-		/* '#' Separator, put high and low components of checksum */
-		put_debug_char('#');
-		put_debug_char(highhex(checksum));
-		put_debug_char(lowhex(checksum));
-	}
-	while ((get_debug_char()) != '+');	/* While no ack */
-}
-
-/* A bus error has occurred - perform a longjmp to return execution and
-   allow handling of the error */
-static void kgdb_handle_bus_error(void)
-{
-	longjmp(rem_com_env, 1);
-}
-
-/* Translate SH-3/4 exception numbers to unix-like signal values */
-static int compute_signal(const int excep_code)
-{
-	int sigval;
-
-	switch (excep_code) {
-
-	case INVALID_INSN_VEC:
-	case INVALID_SLOT_VEC:
-		sigval = SIGILL;
-		break;
-	case ADDRESS_ERROR_LOAD_VEC:
-	case ADDRESS_ERROR_STORE_VEC:
-		sigval = SIGSEGV;
-		break;
-
-	case SERIAL_BREAK_VEC:
-	case NMI_VEC:
-		sigval = SIGINT;
-		break;
-
-	case USER_BREAK_VEC:
-	case TRAP_VEC:
-		sigval = SIGTRAP;
-		break;
-
-	default:
-		sigval = SIGBUS;	/* "software generated" */
-		break;
-	}
-
-	return (sigval);
-}
-
-/* Make a local copy of the registers passed into the handler (bletch) */
-static void kgdb_regs_to_gdb_regs(const struct kgdb_regs *regs,
-				  int *gdb_regs)
-{
-	gdb_regs[R0] = regs->regs[R0];
-	gdb_regs[R1] = regs->regs[R1];
-	gdb_regs[R2] = regs->regs[R2];
-	gdb_regs[R3] = regs->regs[R3];
-	gdb_regs[R4] = regs->regs[R4];
-	gdb_regs[R5] = regs->regs[R5];
-	gdb_regs[R6] = regs->regs[R6];
-	gdb_regs[R7] = regs->regs[R7];
-	gdb_regs[R8] = regs->regs[R8];
-	gdb_regs[R9] = regs->regs[R9];
-	gdb_regs[R10] = regs->regs[R10];
-	gdb_regs[R11] = regs->regs[R11];
-	gdb_regs[R12] = regs->regs[R12];
-	gdb_regs[R13] = regs->regs[R13];
-	gdb_regs[R14] = regs->regs[R14];
-	gdb_regs[R15] = regs->regs[R15];
-	gdb_regs[PC] = regs->pc;
-	gdb_regs[PR] = regs->pr;
-	gdb_regs[GBR] = regs->gbr;
-	gdb_regs[MACH] = regs->mach;
-	gdb_regs[MACL] = regs->macl;
-	gdb_regs[SR] = regs->sr;
-	gdb_regs[VBR] = regs->vbr;
-}
-
-/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
-static void gdb_regs_to_kgdb_regs(const int *gdb_regs,
-				  struct kgdb_regs *regs)
-{
-	regs->regs[R0] = gdb_regs[R0];
-	regs->regs[R1] = gdb_regs[R1];
-	regs->regs[R2] = gdb_regs[R2];
-	regs->regs[R3] = gdb_regs[R3];
-	regs->regs[R4] = gdb_regs[R4];
-	regs->regs[R5] = gdb_regs[R5];
-	regs->regs[R6] = gdb_regs[R6];
-	regs->regs[R7] = gdb_regs[R7];
-	regs->regs[R8] = gdb_regs[R8];
-	regs->regs[R9] = gdb_regs[R9];
-	regs->regs[R10] = gdb_regs[R10];
-	regs->regs[R11] = gdb_regs[R11];
-	regs->regs[R12] = gdb_regs[R12];
-	regs->regs[R13] = gdb_regs[R13];
-	regs->regs[R14] = gdb_regs[R14];
-	regs->regs[R15] = gdb_regs[R15];
-	regs->pc = gdb_regs[PC];
-	regs->pr = gdb_regs[PR];
-	regs->gbr = gdb_regs[GBR];
-	regs->mach = gdb_regs[MACH];
-	regs->macl = gdb_regs[MACL];
-	regs->sr = gdb_regs[SR];
-	regs->vbr = gdb_regs[VBR];
-}
-
-#ifdef CONFIG_KGDB_THREAD
-/* Make a local copy of registers from the specified thread */
-asmlinkage void ret_from_fork(void);
-static void thread_regs_to_gdb_regs(const struct task_struct *thread,
-				    int *gdb_regs)
-{
-	int regno;
-	int *tregs;
-
-	/* Initialize to zero */
-	for (regno = 0; regno < MAXREG; regno++)
-		gdb_regs[regno] = 0;
-
-	/* Just making sure... */
-	if (thread == NULL)
-		return;
-
-	/* A new fork has pt_regs on the stack from a fork() call */
-	if (thread->thread.pc == (unsigned long)ret_from_fork) {
-
-		int vbr_val;
-		struct pt_regs *kregs;
-		kregs = (struct pt_regs*)thread->thread.sp;
-
-		gdb_regs[R0] = kregs->regs[R0];
-		gdb_regs[R1] = kregs->regs[R1];
-		gdb_regs[R2] = kregs->regs[R2];
-		gdb_regs[R3] = kregs->regs[R3];
-		gdb_regs[R4] = kregs->regs[R4];
-		gdb_regs[R5] = kregs->regs[R5];
-		gdb_regs[R6] = kregs->regs[R6];
-		gdb_regs[R7] = kregs->regs[R7];
-		gdb_regs[R8] = kregs->regs[R8];
-		gdb_regs[R9] = kregs->regs[R9];
-		gdb_regs[R10] = kregs->regs[R10];
-		gdb_regs[R11] = kregs->regs[R11];
-		gdb_regs[R12] = kregs->regs[R12];
-		gdb_regs[R13] = kregs->regs[R13];
-		gdb_regs[R14] = kregs->regs[R14];
-		gdb_regs[R15] = kregs->regs[R15];
-		gdb_regs[PC] = kregs->pc;
-		gdb_regs[PR] = kregs->pr;
-		gdb_regs[GBR] = kregs->gbr;
-		gdb_regs[MACH] = kregs->mach;
-		gdb_regs[MACL] = kregs->macl;
-		gdb_regs[SR] = kregs->sr;
-
-		asm("stc vbr, %0":"=r"(vbr_val));
-		gdb_regs[VBR] = vbr_val;
-		return;
-	}
-
-	/* Otherwise, we have only some registers from switch_to() */
-	tregs = (int *)thread->thread.sp;
-	gdb_regs[R15] = (int)tregs;
-	gdb_regs[R14] = *tregs++;
-	gdb_regs[R13] = *tregs++;
-	gdb_regs[R12] = *tregs++;
-	gdb_regs[R11] = *tregs++;
-	gdb_regs[R10] = *tregs++;
-	gdb_regs[R9] = *tregs++;
-	gdb_regs[R8] = *tregs++;
-	gdb_regs[PR] = *tregs++;
-	gdb_regs[GBR] = *tregs++;
-	gdb_regs[PC] = thread->thread.pc;
-}
-#endif /* CONFIG_KGDB_THREAD */
-
-/* Calculate the new address for after a step */
-static short *get_step_address(void)
-{
-	short op = *(short *) trap_registers.pc;
-	long addr;
-
-	/* BT */
-	if (OPCODE_BT(op)) {
-		if (trap_registers.sr & SR_T_BIT_MASK)
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 2;
-	}
-
-	/* BTS */
-	else if (OPCODE_BTS(op)) {
-		if (trap_registers.sr & SR_T_BIT_MASK)
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 4;	/* Not in delay slot */
-	}
-
-	/* BF */
-	else if (OPCODE_BF(op)) {
-		if (!(trap_registers.sr & SR_T_BIT_MASK))
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 2;
-	}
-
-	/* BFS */
-	else if (OPCODE_BFS(op)) {
-		if (!(trap_registers.sr & SR_T_BIT_MASK))
-			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
-		else
-			addr = trap_registers.pc + 4;	/* Not in delay slot */
-	}
-
-	/* BRA */
-	else if (OPCODE_BRA(op))
-		addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op);
-
-	/* BRAF */
-	else if (OPCODE_BRAF(op))
-		addr = trap_registers.pc + 4
-		    + trap_registers.regs[OPCODE_BRAF_REG(op)];
-
-	/* BSR */
-	else if (OPCODE_BSR(op))
-		addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op);
-
-	/* BSRF */
-	else if (OPCODE_BSRF(op))
-		addr = trap_registers.pc + 4
-		    + trap_registers.regs[OPCODE_BSRF_REG(op)];
-
-	/* JMP */
-	else if (OPCODE_JMP(op))
-		addr = trap_registers.regs[OPCODE_JMP_REG(op)];
-
-	/* JSR */
-	else if (OPCODE_JSR(op))
-		addr = trap_registers.regs[OPCODE_JSR_REG(op)];
-
-	/* RTS */
-	else if (OPCODE_RTS(op))
-		addr = trap_registers.pr;
-
-	/* RTE */
-	else if (OPCODE_RTE(op))
-		addr = trap_registers.regs[15];
-
-	/* Other */
-	else
-		addr = trap_registers.pc + 2;
-
-	kgdb_flush_icache_range(addr, addr + 2);
-	return (short *) addr;
-}
-
-/* Set up a single-step.  Replace the instruction immediately after the 
-   current instruction (i.e. next in the expected flow of control) with a
-   trap instruction, so that returning will cause only a single instruction
-   to be executed. Note that this model is slightly broken for instructions
-   with delay slots (e.g. B[TF]S, BSR, BRA etc), where both the branch
-   and the instruction in the delay slot will be executed. */
-static void do_single_step(void)
-{
-	unsigned short *addr = 0;
-
-	/* Determine where the target instruction will send us to */
-	addr = get_step_address();
-	stepped_address = (int)addr;
-
-	/* Replace it */
-	stepped_opcode = *(short *)addr;
-	*addr = STEP_OPCODE;
-
-	/* Flush and return */
-	kgdb_flush_icache_range((long) addr, (long) addr + 2);
-	return;
-}
-
-/* Undo a single step */
-static void undo_single_step(void)
-{
-	/* If we have stepped, put back the old instruction */
-	/* Use stepped_address in case we stopped elsewhere */
-	if (stepped_opcode != 0) {
-		*(short*)stepped_address = stepped_opcode;
-		kgdb_flush_icache_range(stepped_address, stepped_address + 2);
-	}
-	stepped_opcode = 0;
-}
-
-/* Send a signal message */
-static void send_signal_msg(const int signum)
-{
-#ifndef CONFIG_KGDB_THREAD
-	out_buffer[0] = 'S';
-	out_buffer[1] = highhex(signum);
-	out_buffer[2] = lowhex(signum);
-	out_buffer[3] = 0;
-	put_packet(out_buffer);
-#else /* CONFIG_KGDB_THREAD */
-	int threadid;
-	threadref thref;
-	char *out = out_buffer;
-	const char *tstring = "thread";
-
-	*out++ = 'T';
-	*out++ = highhex(signum);
-	*out++ = lowhex(signum);
-
-	while (*tstring) {
-		*out++ = *tstring++;
-	}
-	*out++ = ':';
-
-	threadid = trapped_thread->pid;
-	if (threadid == 0) threadid = PID_MAX;
-	int_to_threadref(&thref, threadid);
-	pack_threadid(out, &thref);
-	out += BUF_THREAD_ID_SIZE;
-	*out++ = ';';
-
-	*out = 0;
-	put_packet(out_buffer);
-#endif /* CONFIG_KGDB_THREAD */
-}
-
-/* Reply that all was well */
-static void send_ok_msg(void)
-{
-	strcpy(out_buffer, "OK");
-	put_packet(out_buffer);
-}
-
-/* Reply that an error occurred */
-static void send_err_msg(void)
-{
-	strcpy(out_buffer, "E01");
-	put_packet(out_buffer);
-}
-
-/* Empty message indicates unrecognised command */
-static void send_empty_msg(void)
-{
-	put_packet("");
-}
-
-/* Read memory due to 'm' message */
-static void read_mem_msg(void)
-{
-	char *ptr;
-	int addr;
-	int length;
-
-	/* Jmp, disable bus error handler */
-	if (setjmp(rem_com_env) == 0) {
-
-		kgdb_nofault = 1;
-
-		/* Walk through, have m<addr>,<length> */
-		ptr = &in_buffer[1];
-		if (hex_to_int(&ptr, &addr) && (*ptr++ == ','))
-			if (hex_to_int(&ptr, &length)) {
-				ptr = 0;
-				if (length * 2 > OUTBUFMAX)
-					length = OUTBUFMAX / 2;
-				mem_to_hex((char *) addr, out_buffer, length);
-			}
-		if (ptr)
-			send_err_msg();
-		else
-			put_packet(out_buffer);
-	} else
-		send_err_msg();
-
-	/* Restore bus error handler */
-	kgdb_nofault = 0;
-}
-
-/* Write memory due to 'M' or 'X' message */
-static void write_mem_msg(int binary)
-{
-	char *ptr;
-	int addr;
-	int length;
-
-	if (setjmp(rem_com_env) == 0) {
-
-		kgdb_nofault = 1;
-
-		/* Walk through, have M<addr>,<length>:<data> */
-		ptr = &in_buffer[1];
-		if (hex_to_int(&ptr, &addr) && (*ptr++ == ','))
-			if (hex_to_int(&ptr, &length) && (*ptr++ == ':')) {
-				if (binary)
-					ebin_to_mem(ptr, (char*)addr, length);
-				else
-					hex_to_mem(ptr, (char*)addr, length);
-				kgdb_flush_icache_range(addr, addr + length);
-				ptr = 0;
-				send_ok_msg();
-			}
-		if (ptr)
-			send_err_msg();
-	} else
-		send_err_msg();
-
-	/* Restore bus error handler */
-	kgdb_nofault = 0;
-}
-
-/* Continue message  */
-static void continue_msg(void)
-{
-	/* Try to read optional parameter, PC unchanged if none */
-	char *ptr = &in_buffer[1];
-	int addr;
-
-	if (hex_to_int(&ptr, &addr))
-		trap_registers.pc = addr;
-}
-
-/* Continue message with signal */
-static void continue_with_sig_msg(void)
-{
-	int signal;
-	char *ptr = &in_buffer[1];
-	int addr;
-
-	/* Report limitation */
-	kgdb_to_gdb("Cannot force signal in kgdb, continuing anyway.\n");
-
-	/* Signal */
-	hex_to_int(&ptr, &signal);
-	if (*ptr == ';')
-		ptr++;
-
-	/* Optional address */
-	if (hex_to_int(&ptr, &addr))
-		trap_registers.pc = addr;
-}
-
-/* Step message */
-static void step_msg(void)
-{
-	continue_msg();
-	do_single_step();
-}
-
-/* Step message with signal */
-static void step_with_sig_msg(void)
-{
-	continue_with_sig_msg();
-	do_single_step();
-}
-
-/* Send register contents */
-static void send_regs_msg(void)
-{
-#ifdef CONFIG_KGDB_THREAD
-	if (!current_thread)
-		kgdb_regs_to_gdb_regs(&trap_registers, registers);
-	else
-		thread_regs_to_gdb_regs(current_thread, registers);
-#else
-	kgdb_regs_to_gdb_regs(&trap_registers, registers);
-#endif
-
-	mem_to_hex((char *) registers, out_buffer, NUMREGBYTES);
-	put_packet(out_buffer);
-}
-
-/* Set register contents - currently can't set other thread's registers */
-static void set_regs_msg(void)
-{
-#ifdef CONFIG_KGDB_THREAD
-	if (!current_thread) {
-#endif
-		kgdb_regs_to_gdb_regs(&trap_registers, registers);
-		hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
-		gdb_regs_to_kgdb_regs(registers, &trap_registers);
-		send_ok_msg();
-#ifdef CONFIG_KGDB_THREAD
-	} else
-		send_err_msg();
-#endif
-}
-
-
-#ifdef CONFIG_KGDB_THREAD
-
-/* Set the status for a thread */
-void set_thread_msg(void)
-{
-	int threadid;
-	struct task_struct *thread = NULL;
-	char *ptr;
-
-	switch (in_buffer[1]) {
-
-       	/* To select which thread for gG etc messages, i.e. supported */
-	case 'g':
-
-		ptr = &in_buffer[2];
-		hex_to_int(&ptr, &threadid);
-		thread = get_thread(threadid);
-
-		/* If we haven't found it */
-		if (!thread) {
-			send_err_msg();
-			break;
-		}
-
-		/* Set current_thread (or not) */
-		if (thread == trapped_thread)
-			current_thread = NULL;
-		else
-			current_thread = thread;
-		send_ok_msg();
-		break;
-
-	/* To select which thread for cCsS messages, i.e. unsupported */
-	case 'c':
-		send_ok_msg();
-		break;
-
-	default:
-		send_empty_msg();
-		break;
-	}
-}
-
-/* Is a thread alive? */
-static void thread_status_msg(void)
-{
-	char *ptr;
-	int threadid;
-	struct task_struct *thread = NULL;
-
-	ptr = &in_buffer[1];
-	hex_to_int(&ptr, &threadid);
-	thread = get_thread(threadid);
-	if (thread)
-		send_ok_msg();
-	else
-		send_err_msg();
-}
-/* Send the current thread ID */
-static void thread_id_msg(void)
-{
-	int threadid;
-	threadref thref;
-
-	out_buffer[0] = 'Q';
-	out_buffer[1] = 'C';
-
-	if (current_thread)
-		threadid = current_thread->pid;
-	else if (trapped_thread)
-		threadid = trapped_thread->pid;
-	else /* Impossible, but just in case! */
-	{
-		send_err_msg();
-		return;
-	}
-
-	/* Translate pid 0 to PID_MAX for gdb */
-	if (threadid == 0) threadid = PID_MAX;
-
-	int_to_threadref(&thref, threadid);
-	pack_threadid(out_buffer + 2, &thref);
-	out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0';
-	put_packet(out_buffer);
-}
-
-/* Send thread info */
-static void thread_info_msg(void)
-{
-	struct task_struct *thread = NULL;
-	int threadid;
-	char *pos;
-	threadref thref;
-
-	/* Start with 'm' */
-	out_buffer[0] = 'm';
-	pos = &out_buffer[1];
-
-	/* For all possible thread IDs - this will overrun if > 44 threads! */
-	/* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */
-	for (threadid = 1; threadid <= PID_MAX; threadid++) {
-
-		read_lock(&tasklist_lock);
-		thread = get_thread(threadid);
-		read_unlock(&tasklist_lock);
-
-		/* If it's a valid thread */
-		if (thread) {
-			int_to_threadref(&thref, threadid);
-			pack_threadid(pos, &thref);
-			pos += BUF_THREAD_ID_SIZE;
-			*pos++ = ',';
-		}
-	}
-	*--pos = 0;		/* Lose final comma */
-	put_packet(out_buffer);
-
-}
-
-/* Return printable info for gdb's 'info threads' command */
-static void thread_extra_info_msg(void)
-{
-	int threadid;
-	struct task_struct *thread = NULL;
-	char buffer[20], *ptr;
-	int i;
-
-	/* Extract thread ID */
-	ptr = &in_buffer[17];
-	hex_to_int(&ptr, &threadid);
-	thread = get_thread(threadid);
-
-	/* If we don't recognise it, say so */
-	if (thread == NULL)
-		strcpy(buffer, "(unknown)");
-	else
-		strcpy(buffer, thread->comm);
-
-	/* Construct packet */
-	for (i = 0, ptr = out_buffer; buffer[i]; i++)
-		ptr = pack_hex_byte(ptr, buffer[i]);
-
-	if (thread->thread.pc == (unsigned long)ret_from_fork) {
-		strcpy(buffer, "<new fork>");
-		for (i = 0; buffer[i]; i++)
-			ptr = pack_hex_byte(ptr, buffer[i]);
-	}
-
-	*ptr = '\0';
-	put_packet(out_buffer);
-}
-
-/* Handle all qFooBarBaz messages - have to use an if statement as
-   opposed to a switch because q messages can have > 1 char id. */
-static void query_msg(void)
-{
-	const char *q_start = &in_buffer[1];
-
-	/* qC = return current thread ID */
-	if (strncmp(q_start, "C", 1) == 0)
-		thread_id_msg();
-
-	/* qfThreadInfo = query all threads (first) */
-	else if (strncmp(q_start, "fThreadInfo", 11) == 0)
-		thread_info_msg();
-
-	/* qsThreadInfo = query all threads (subsequent). We know we have sent
-	   them all after the qfThreadInfo message, so there are no to send */
-	else if (strncmp(q_start, "sThreadInfo", 11) == 0)
-		put_packet("l");	/* el = last */
-
-	/* qThreadExtraInfo = supply printable information per thread */
-	else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0)
-		thread_extra_info_msg();
-
-	/* Unsupported - empty message as per spec */
-	else
-		send_empty_msg();
-}
-#endif /* CONFIG_KGDB_THREAD */
-
-/*
- * Bring up the ports..
- */
-static int kgdb_serial_setup(void)
-{
-	extern int kgdb_console_setup(struct console *co, char *options);
-	struct console dummy;
-
-	kgdb_console_setup(&dummy, 0);
-
-	return 0;
-}
-
-/* The command loop, read and act on requests */
-static void kgdb_command_loop(const int excep_code, const int trapa_value)
-{
-	int sigval;
-
-	if (excep_code == NMI_VEC) {
-#ifndef CONFIG_KGDB_NMI
-		KGDB_PRINTK("Ignoring unexpected NMI?\n");
-		return;
-#else /* CONFIG_KGDB_NMI */
-		if (!kgdb_enabled) {
-			kgdb_enabled = 1;
-			kgdb_init();
-		}
-#endif /* CONFIG_KGDB_NMI */
-	}
-
-	/* Ignore if we're disabled */
-	if (!kgdb_enabled)
-		return;
-
-#ifdef CONFIG_KGDB_THREAD
-	/* Until GDB specifies a thread */
-	current_thread = NULL;
-	trapped_thread = current;
-#endif
-
-	/* Enter GDB mode (e.g. after detach) */
-	if (!kgdb_in_gdb_mode) {
-		/* Do serial setup, notify user, issue preemptive ack */
-		kgdb_serial_setup();
-		KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n",
-			    (kgdb_porttype ? kgdb_porttype->name : ""),
-			    kgdb_portnum, kgdb_baud);
-		kgdb_in_gdb_mode = 1;
-		put_debug_char('+');
-	}
-
-	/* Reply to host that an exception has occurred */
-	sigval = compute_signal(excep_code);
-	send_signal_msg(sigval);
-
-	/* TRAP_VEC exception indicates a software trap inserted in place of
-	   code by GDB so back up PC by one instruction, as this instruction
-	   will later be replaced by its original one.  Do NOT do this for
-	   trap 0xff, since that indicates a compiled-in breakpoint which
-	   will not be replaced (and we would retake the trap forever) */
-	if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) {
-		trap_registers.pc -= 2;
-	}
-
-	/* Undo any stepping we may have done */
-	undo_single_step();
-
-	while (1) {
-
-		out_buffer[0] = 0;
-		get_packet(in_buffer, BUFMAX);
-
-		/* Examine first char of buffer to see what we need to do */
-		switch (in_buffer[0]) {
-
-		case '?':	/* Send which signal we've received */
-			send_signal_msg(sigval);
-			break;
-
-		case 'g':	/* Return the values of the CPU registers */
-			send_regs_msg();
-			break;
-
-		case 'G':	/* Set the value of the CPU registers */
-			set_regs_msg();
-			break;
-
-		case 'm':	/* Read LLLL bytes address AA..AA */
-			read_mem_msg();
-			break;
-
-		case 'M':	/* Write LLLL bytes address AA..AA, ret OK */
-			write_mem_msg(0);	/* 0 = data in hex */
-			break;
-
-		case 'X':	/* Write LLLL bytes esc bin address AA..AA */
-			if (kgdb_bits == '8')
-				write_mem_msg(1); /* 1 = data in binary */
-			else
-				send_empty_msg();
-			break;
-
-		case 'C':	/* Continue, signum included, we ignore it */
-			continue_with_sig_msg();
-			return;
-
-		case 'c':	/* Continue at address AA..AA (optional) */
-			continue_msg();
-			return;
-
-		case 'S':	/* Step, signum included, we ignore it */
-			step_with_sig_msg();
-			return;
-
-		case 's':	/* Step one instruction from AA..AA */
-			step_msg();
-			return;
-
-#ifdef CONFIG_KGDB_THREAD
-
-		case 'H':	/* Task related */
-			set_thread_msg();
-			break;
-
-		case 'T':	/* Query thread status */
-			thread_status_msg();
-			break;
-
-		case 'q':	/* Handle query - currently thread-related */
-			query_msg();
-			break;
-#endif
-
-		case 'k':	/* 'Kill the program' with a kernel ? */
-			break;
-
-		case 'D':	/* Detach from program, send reply OK */
-			kgdb_in_gdb_mode = 0;
-			send_ok_msg();
-			get_debug_char();
-			return;
-
-		default:
-			send_empty_msg();
-			break;
-		}
-	}
-}
-
-/* There has been an exception, most likely a breakpoint. */
-void kgdb_handle_exception(struct pt_regs *regs)
-{
-	int excep_code, vbr_val;
-	int count;
-	int trapa_value = ctrl_inl(TRA);
-
-	/* Copy kernel regs (from stack) */
-	for (count = 0; count < 16; count++)
-		trap_registers.regs[count] = regs->regs[count];
-	trap_registers.pc = regs->pc;
-	trap_registers.pr = regs->pr;
-	trap_registers.sr = regs->sr;
-	trap_registers.gbr = regs->gbr;
-	trap_registers.mach = regs->mach;
-	trap_registers.macl = regs->macl;
-
-	asm("stc vbr, %0":"=r"(vbr_val));
-	trap_registers.vbr = vbr_val;
-
-	/* Get excode for command loop call, user access */
-	asm("stc r2_bank, %0":"=r"(excep_code));
-	kgdb_excode = excep_code;
-
-	/* Other interesting environment items for reference */
-	asm("stc r6_bank, %0":"=r"(kgdb_g_imask));
-	kgdb_current = current;
-	kgdb_trapa_val = trapa_value;
-
-	/* Act on the exception */
-	kgdb_command_loop(excep_code >> 5, trapa_value);
-
-	kgdb_current = NULL;
-
-	/* Copy back the (maybe modified) registers */
-	for (count = 0; count < 16; count++)
-		regs->regs[count] = trap_registers.regs[count];
-	regs->pc = trap_registers.pc;
-	regs->pr = trap_registers.pr;
-	regs->sr = trap_registers.sr;
-	regs->gbr = trap_registers.gbr;
-	regs->mach = trap_registers.mach;
-	regs->macl = trap_registers.macl;
-
-	vbr_val = trap_registers.vbr;
-	asm("ldc %0, vbr": :"r"(vbr_val));
-
-	return;
-}
-
-/* Trigger a breakpoint by function */
-void breakpoint(void)
-{
-	if (!kgdb_enabled) {
-		kgdb_enabled = 1;
-		kgdb_init();
-	}
-	BREAKPOINT();
-}
-
-/* Initialise the KGDB data structures and serial configuration */
-int kgdb_init(void)
-{
-	if (!kgdb_enabled)
-		return 1;
-
-	in_nmi = 0;
-	kgdb_nofault = 0;
-	stepped_opcode = 0;
-	kgdb_in_gdb_mode = 0;
-
-	if (kgdb_serial_setup() != 0) {
-		KGDB_PRINTK("serial setup error\n");
-		return -1;
-	}
-
-	/* Init ptr to exception handler */
-	kgdb_debug_hook = kgdb_handle_exception;
-	kgdb_bus_err_hook = kgdb_handle_bus_error;
-
-	/* Enter kgdb now if requested, or just report init done */
-	if (kgdb_halt) {
-		kgdb_in_gdb_mode = 1;
-		put_debug_char('+');
-		breakpoint();
-	}
-	else
-	{
-		KGDB_PRINTK("stub is initialized.\n");
-	}
-
-	return 0;
-}
-
-/* Make function available for "user messages"; console will use it too. */
-
-char gdbmsgbuf[BUFMAX];
-#define MAXOUT ((BUFMAX-2)/2)
-
-static void kgdb_msg_write(const char *s, unsigned count)
-{
-	int i;
-	int wcount;
-	char *bufptr;
-
-	/* 'O'utput */
-	gdbmsgbuf[0] = 'O';
-
-	/* Fill and send buffers... */
-	while (count > 0) {
-		bufptr = gdbmsgbuf + 1;
-
-		/* Calculate how many this time */
-		wcount = (count > MAXOUT) ? MAXOUT : count;
-		
-		/* Pack in hex chars */
-		for (i = 0; i < wcount; i++)
-			bufptr = pack_hex_byte(bufptr, s[i]);
-		*bufptr = '\0';
-
-		/* Move up */
-		s += wcount;
-		count -= wcount;
-
-		/* Write packet */
-		put_packet(gdbmsgbuf);
-	}
-}
-
-static void kgdb_to_gdb(const char *s)
-{
-	kgdb_msg_write(s, strlen(s));
-}
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
-void kgdb_console_write(struct console *co, const char *s, unsigned count)
-{
-	/* Bail if we're not talking to GDB */
-	if (!kgdb_in_gdb_mode)
-		return;
-
-	kgdb_msg_write(s, count);
-}
-#endif
Index: linux-2.6.14/arch/sh/kernel/Makefile
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/Makefile
+++ linux-2.6.14/arch/sh/kernel/Makefile
@@ -13,7 +13,7 @@ obj-y				+= cpu/
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
 obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
-obj-$(CONFIG_SH_KGDB)		+= kgdb_stub.o kgdb_jmp.o
+obj-$(CONFIG_KGDB)		+= kgdb.o kgdb-jmp.o
 obj-$(CONFIG_SH_CPU_FREQ)	+= cpufreq.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
Index: linux-2.6.14/arch/sh/kernel/setup.c
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/setup.c
+++ linux-2.6.14/arch/sh/kernel/setup.c
@@ -27,10 +27,6 @@
 #include <asm/irq.h>
 #include <asm/setup.h>
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-static int kgdb_parse_options(char *options);
-#endif
 extern void * __rd_start, * __rd_end;
 /*
  * Machine setup..
@@ -557,93 +553,3 @@ struct seq_operations cpuinfo_op = {
 	.show	= show_cpuinfo,
 };
 #endif /* CONFIG_PROC_FS */
-
-#ifdef CONFIG_SH_KGDB
-/*
- * Parse command-line kgdb options.  By default KGDB is enabled,
- * entered on error (or other action) using default serial info.
- * The command-line option can include a serial port specification
- * and an action to override default or configured behavior.
- */
-struct kgdb_sermap kgdb_sci_sermap =
-{ "ttySC", 5, kgdb_sci_setup, NULL };
-
-struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap;
-struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap;
-
-void kgdb_register_sermap(struct kgdb_sermap *map)
-{
-	struct kgdb_sermap *last;
-
-	for (last = kgdb_serlist; last->next; last = last->next)
-		;
-	last->next = map;
-	if (!map->namelen) {
-		map->namelen = strlen(map->name);
-	}
-}
-
-static int __init kgdb_parse_options(char *options)
-{
-	char c;
-	int baud;
-
-	/* Check for port spec (or use default) */
-
-	/* Determine port type and instance */
-	if (!memcmp(options, "tty", 3)) {
-		struct kgdb_sermap *map = kgdb_serlist;
-
-		while (map && memcmp(options, map->name, map->namelen))
-			map = map->next;
-
-		if (!map) {
-			KGDB_PRINTK("unknown port spec in %s\n", options);
-			return -1;
-		}
-
-		kgdb_porttype = map;
-		kgdb_serial_setup = map->setup_fn;
-		kgdb_portnum = options[map->namelen] - '0';
-		options += map->namelen + 1;
-
-		options = (*options == ',') ? options+1 : options;
-		
-		/* Read optional parameters (baud/parity/bits) */
-		baud = simple_strtoul(options, &options, 10);
-		if (baud != 0) {
-			kgdb_baud = baud;
-
-			c = toupper(*options);
-			if (c == 'E' || c == 'O' || c == 'N') {
-				kgdb_parity = c;
-				options++;
-			}
-
-			c = *options;
-			if (c == '7' || c == '8') {
-				kgdb_bits = c;
-				options++;
-			}
-			options = (*options == ',') ? options+1 : options;
-		}
-	}
-
-	/* Check for action specification */
-	if (!memcmp(options, "halt", 4)) {
-		kgdb_halt = 1;
-		options += 4;
-	} else if (!memcmp(options, "disabled", 8)) {
-		kgdb_enabled = 0;
-		options += 8;
-	}
-
-	if (*options) {
-                KGDB_PRINTK("ignored unknown options: %s\n", options);
-		return 0;
-	}
-	return 1;
-}
-__setup("kgdb=", kgdb_parse_options);
-#endif /* CONFIG_SH_KGDB */
-
Index: linux-2.6.14/arch/sh/kernel/time.c
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/time.c
+++ linux-2.6.14/arch/sh/kernel/time.c
@@ -34,9 +34,6 @@
 #include <asm/rtc.h>
 #include <asm/freq.h>
 #include <asm/cpu/timer.h>
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#endif
 
 #include <linux/timex.h>
 #include <linux/irq.h>
@@ -643,12 +640,4 @@ void __init time_init(void)
 	ctrl_outl(interval, TMU0_TCOR);
 	ctrl_outl(interval, TMU0_TCNT);
 	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
-
-#if defined(CONFIG_SH_KGDB)
-	/*
-	 * Set up kgdb as requested. We do it here because the serial
-	 * init uses the timer vars we just set up for figuring baud.
-	 */
-	kgdb_init();
-#endif
 }
Index: linux-2.6.14/arch/sh/kernel/traps.c
===================================================================
--- linux-2.6.14.orig/arch/sh/kernel/traps.c
+++ linux-2.6.14/arch/sh/kernel/traps.c
@@ -27,6 +27,7 @@
 #include <linux/spinlock.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/kgdb.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -35,17 +36,8 @@
 #include <asm/processor.h>
 #include <asm/sections.h>
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#define CHK_REMOTE_DEBUG(regs)                                               \
-{                                                                            \
-  if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \
-  {                                                                          \
-    (*kgdb_debug_hook)(regs);                                                \
-  }                                                                          \
-}
-#else
-#define CHK_REMOTE_DEBUG(regs)
+#ifndef CONFIG_KGDB
+#define kgdb_handle_exception(t, s, e, r)
 #endif
 
 #define DO_ERROR(trapnr, signr, str, name, tsk)				\
@@ -66,7 +58,7 @@ asmlinkage void do_##name(unsigned long 
 	local_irq_enable();						\
 	tsk->thread.error_code = error_code;				\
 	tsk->thread.trap_no = trapnr;					\
-        CHK_REMOTE_DEBUG(&regs);					\
+	kgdb_handle_exception(trapnr, signr, error_code, &regs);	\
 	force_sig(signr, tsk);						\
 	die_if_no_fixup(str,&regs,error_code);				\
 }
@@ -93,10 +85,12 @@ void die(const char * str, struct pt_reg
 {
 	static int die_counter;
 
+#ifdef CONFIG_KGDB
+	kgdb_handle_exception(1, SIGTRAP, err, regs);
+#endif
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
-	CHK_REMOTE_DEBUG(regs);
 	show_regs(regs);
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
Index: linux-2.6.14/arch/sh/Makefile
===================================================================
--- linux-2.6.14.orig/arch/sh/Makefile
+++ linux-2.6.14/arch/sh/Makefile
@@ -23,7 +23,6 @@ cflags-$(CONFIG_CPU_SH4)		+= -m4 \
 	$(call cc-option,-mno-implicit-fp,-m4-nofpu)
 
 cflags-$(CONFIG_SH_DSP)			+= -Wa,-dsp
-cflags-$(CONFIG_SH_KGDB)		+= -g
 
 cflags-$(CONFIG_MORE_COMPILE_OPTIONS)	+= \
 	$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
Index: linux-2.6.14/arch/sh/mm/extable.c
===================================================================
--- linux-2.6.14.orig/arch/sh/mm/extable.c
+++ linux-2.6.14/arch/sh/mm/extable.c
@@ -6,6 +6,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/kgdb.h>
 #include <asm/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
@@ -17,6 +18,12 @@ int fixup_exception(struct pt_regs *regs
 		regs->pc = fixup->fixup;
 		return 1;
 	}
+#ifdef CONFIG_KGDB
+	if (atomic_read(&debugger_active) && kgdb_may_fault)
+		/* Restore our previous state. */
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		/* Never reached. */
+#endif
 
 	return 0;
 }
Index: linux-2.6.14/arch/sh/mm/fault.c
===================================================================
--- linux-2.6.14.orig/arch/sh/mm/fault.c
+++ linux-2.6.14/arch/sh/mm/fault.c
@@ -28,7 +28,6 @@
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
-#include <asm/kgdb.h>
 
 extern void die(const char *,struct pt_regs *,long);
 
@@ -45,11 +44,6 @@ asmlinkage void do_page_fault(struct pt_
 	struct vm_area_struct * vma;
 	unsigned long page;
 
-#ifdef CONFIG_SH_KGDB
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 	tsk = current;
 	mm = tsk->mm;
 
@@ -153,6 +147,7 @@ no_context:
 	}
 	die("Oops", regs, writeaccess);
 	do_exit(SIGKILL);
+	dump_stack();
 
 /*
  * We ran out of memory, or some other thing happened to us that made
@@ -199,11 +194,6 @@ asmlinkage int __do_page_fault(struct pt
 	pte_t *pte;
 	pte_t entry;
 
-#ifdef CONFIG_SH_KGDB
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 #ifdef CONFIG_SH_STORE_QUEUES
 	addrmax = P4SEG_STORE_QUE + 0x04000000;
 #endif
Index: linux-2.6.14/arch/sh/mm/fault-nommu.c
===================================================================
--- linux-2.6.14.orig/arch/sh/mm/fault-nommu.c
+++ linux-2.6.14/arch/sh/mm/fault-nommu.c
@@ -29,10 +29,6 @@
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 
-#if defined(CONFIG_SH_KGDB)
-#include <asm/kgdb.h>
-#endif
-
 extern void die(const char *,struct pt_regs *,long);
 
 /*
@@ -43,11 +39,6 @@ extern void die(const char *,struct pt_r
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
 			      unsigned long address)
 {
-#if defined(CONFIG_SH_KGDB)
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 	/*
 	 * Oops. The kernel tried to access some bad page. We'll have to
 	 * terminate things with extreme prejudice.
@@ -69,11 +60,6 @@ asmlinkage void do_page_fault(struct pt_
 asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
 			       unsigned long address)
 {
-#if defined(CONFIG_SH_KGDB)
-	if (kgdb_nofault && kgdb_bus_err_hook)
-		kgdb_bus_err_hook();
-#endif
-
 	if (address >= TASK_SIZE)
 		return 1;
 
Index: linux-2.6.14/Documentation/DocBook/kgdb.tmpl
===================================================================
--- linux-2.6.14.orig/Documentation/DocBook/kgdb.tmpl
+++ linux-2.6.14/Documentation/DocBook/kgdb.tmpl
@@ -122,6 +122,10 @@
     serial driver, pass in: <constant>kgdbwait</constant>.
     </para>
     <para>
+    To specify the values of the SH SCI(F) serial port at boot:
+    <constant>kgdbsci=0,115200</constant>.
+    </para>
+    <para>
     To specify the values of the serial port at boot:
     <constant>kgdb8250=io,3f8,115200,3</constant>.
     On IA64 this could also be:
@@ -171,6 +175,18 @@
     application program.
     </para>
   </chapter>
+  <chapter id="ArchitectureNotes">
+    <title>Architecture specific notes</title>
+      <para>
+      SuperH: The NMI switch found on some boards can be used to trigger an
+      initial breakpoint.  Subsequent triggers do nothing.  If console
+      is enabled on the SCI(F) serial port, and that is the port being used
+      for KGDB, then you must trigger a breakpoint via sysrq, NMI, or
+      some other method prior to connecting, or echo a control-c to the
+      serial port.  Also, to use the SCI(F) port for KGDB, the
+      <symbol>CONFIG_SERIAL_SH_SCI</symbol> driver must be enabled.
+      </para>
+  </chapter>
   <chapter id="CommonBackEndReq">
     <title>The common backend (required)</title>
       <para>
Index: linux-2.6.14/drivers/serial/sh-sci.c
===================================================================
--- linux-2.6.14.orig/drivers/serial/sh-sci.c
+++ linux-2.6.14/drivers/serial/sh-sci.c
@@ -42,6 +42,7 @@
 #include <linux/delay.h>
 #include <linux/console.h>
 #include <linux/bitops.h>
+#include <linux/kgdb.h>
 
 #ifdef CONFIG_CPU_FREQ
 #include <linux/notifier.h>
@@ -65,14 +66,16 @@
 
 #include "sh-sci.h"
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-
-static int kgdb_get_char(struct sci_port *port);
-static void kgdb_put_char(struct sci_port *port, char c);
-static void kgdb_handle_error(struct sci_port *port);
-static struct sci_port *kgdb_sci_port;
-#endif /* CONFIG_SH_KGDB */
+#ifdef CONFIG_KGDB_SH_SCI
+/* Speed of the UART. */
+static int kgdbsci_baud = CONFIG_KGDB_BAUDRATE
+
+/* Index of the UART, matches ttySCX naming. */
+static int kgdbsci_ttySC = CONFIG_KGDB_PORT_NUM;
+
+/* Make life easier on us. */
+#define KGDBPORT	sci_ports[kgdbsci_ttySC]
+#endif /* CONFIG_KGDB_SH_SCI */
 
 #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 static struct sci_port *serial_console_port = 0;
@@ -85,18 +88,15 @@ static void sci_start_rx(struct uart_por
 static void sci_stop_rx(struct uart_port *port);
 static int sci_request_irq(struct sci_port *port);
 static void sci_free_irq(struct sci_port *port);
+static void sci_set_termios(struct uart_port *port, struct termios *termios,
+			    struct termios *old);
+static int kgdbsci_init(void);
 
 static struct sci_port sci_ports[SCI_NPORTS];
 static struct uart_driver sci_uart_driver;
 
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
-
-static void handle_error(struct uart_port *port)
-{				/* Clear error flags */
-	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
-}
-
-static int get_char(struct uart_port *port)
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_KGDB_SH_SCI)
+static int get_char_for_gdb(struct uart_port *port)
 {
 	unsigned long flags;
 	unsigned short status;
@@ -106,7 +106,8 @@ static int get_char(struct uart_port *po
         do {
 		status = sci_in(port, SCxSR);
 		if (status & SCxSR_ERRORS(port)) {
-			handle_error(port);
+			/* Clear error flags. */
+			sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
 			continue;
 		}
 	} while (!(status & SCxSR_RDxF(port)));
@@ -117,21 +118,7 @@ static int get_char(struct uart_port *po
 
 	return c;
 }
-
-/* Taken from sh-stub.c of GDB 4.18 */
-static const char hexchars[] = "0123456789abcdef";
-
-static __inline__ char highhex(int  x)
-{
-	return hexchars[(x >> 4) & 0xf];
-}
-
-static __inline__ char lowhex(int  x)
-{
-	return hexchars[x & 0xf];
-}
-
-#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_KGDB_SH_SCI */
 
 /*
  * Send the packet in buffer.  The host gets one chance to read it.
@@ -163,21 +150,14 @@ static void put_string(struct sci_port *
 	const unsigned char *p = buffer;
 	int i;
 
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+#ifdef CONFIG_SH_STANDARD_BIOS
 	int checksum;
-	int usegdb=0;
+	const char hexchars[] = "0123456789abcdef";
 
-#ifdef CONFIG_SH_STANDARD_BIOS
     	/* This call only does a trap the first time it is
 	 * called, and so is safe to do here unconditionally
 	 */
-	usegdb |= sh_bios_in_gdb_mode();
-#endif
-#ifdef CONFIG_SH_KGDB
-	usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port));
-#endif
-
-	if (usegdb) {
+	if (sh_bios_in_gdb_mode()) {
 	    /*  $<packet info>#<checksum>. */
 	    do {
 		unsigned char c;
@@ -189,18 +169,18 @@ static void put_string(struct sci_port *
 			int h, l;
 
 			c = *p++;
-			h = highhex(c);
-			l = lowhex(c);
+			h = hexchars[c >> 4];
+			l = hexchars[c % 16];
 			put_char(port, h);
 			put_char(port, l);
 			checksum += h + l;
 		}
 		put_char(port, '#');
-		put_char(port, highhex(checksum));
-		put_char(port, lowhex(checksum));
+		put_char(port, hexchars[checksum >> 4]);
+		put_char(port, hexchars[checksum & 16]);
 	    } while  (get_char(port) != '+');
 	} else
-#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+#endif /* CONFIG_SH_STANDARD_BIOS */
 	for (i=0; i<count; i++) {
 		if (*p == 10)
 			put_char(port, '\r');
@@ -210,90 +190,163 @@ static void put_string(struct sci_port *
 #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
 
 
-#ifdef CONFIG_SH_KGDB
-
-/* Is the SCI ready, ie is there a char waiting? */
-static int kgdb_is_char_ready(struct sci_port *port)
+#ifdef CONFIG_KGDB_SH_SCI
+static int kgdbsci_read_char(void)
 {
-        unsigned short status = sci_in(port, SCxSR);
-
-        if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port)))
-                kgdb_handle_error(port);
-
-        return (status & SCxSR_RDxF(port));
+	return get_char_for_gdb(&KGDBPORT.port);
 }
 
-/* Write a char */
-static void kgdb_put_char(struct sci_port *port, char c)
+/* Called from kgdbstub.c to put a character, just a wrapper */
+static void kgdbsci_write_char(int c)
 {
-        unsigned short status;
-
-        do
-                status = sci_in(port, SCxSR);
-        while (!(status & SCxSR_TDxE(port)));
+	unsigned short status;
 
-        sci_out(port, SCxTDR, c);
-        sci_in(port, SCxSR);    /* Dummy read */
-        sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+	do
+		status = sci_in(&KGDBPORT.port, SCxSR);
+	while (!(status & SCxSR_TDxE(&KGDBPORT.port)));
+
+	sci_out(&KGDBPORT.port, SCxTDR, c);
+	sci_in(&KGDBPORT.port, SCxSR);	/* Dummy read */
+	sci_out(&KGDBPORT.port, SCxSR, SCxSR_TDxE_CLEAR(&KGDBPORT.port));
 }
 
-/* Get a char if there is one, else ret -1 */
-static int kgdb_get_char(struct sci_port *port)
+#ifndef CONFIG_SERIAL_SH_SCI_CONSOLE
+/* If we don't have console, we never hookup IRQs.  But we need to
+ * hookup one so that we can interrupt the system.
+ */
+static irqreturn_t kgdbsci_rx_interrupt(int irq, void *ptr,
+		struct pt_regs *regs)
 {
-        int c;
-
-        if (kgdb_is_char_ready(port) == 0)
-                c = -1;
-        else {
-                c = sci_in(port, SCxRDR);
-                sci_in(port, SCxSR);    /* Dummy read */
-                sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-        }
+	struct uart_port *port = ptr;
 
-        return c;
-}
+	if (!(sci_in(port, SCxSR) & SCxSR_RDxF(port)))
+		return IRQ_NONE;
 
-/* Called from kgdbstub.c to get a character, i.e. is blocking */
-static int kgdb_sci_getchar(void)
-{
-        volatile int c;
+	if (kgdb_io_ops.init != kgdbsci_init) {
+		/* Throw away the data if another I/O routine is active */
+		get_char_for_gdb(&KGDBPORT.port);
+	} else
+		/* We've got an interrupt, so go ahead and call breakpoint() */
+		breakpoint();
 
-        /* Keep trying to read a character, this could be neater */
-        while ((c = kgdb_get_char(kgdb_sci_port)) < 0);
+	sci_in(port, SCxSR); /* dummy read */
+	sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
 
-        return c;
+	return IRQ_HANDLED;
 }
 
-/* Called from kgdbstub.c to put a character, just a wrapper */
-static void kgdb_sci_putchar(int c)
+static irqreturn_t kgdbsci_mpxed_interrupt(int irq, void *ptr,
+		struct pt_regs *regs)
 {
+        unsigned short ssr_status, scr_status;
+        struct uart_port *port = ptr;
+
+        ssr_status = sci_in(port,SCxSR);
+        scr_status = sci_in(port,SCSCR);
+
+	/* Rx Interrupt */
+        if ((ssr_status&0x0002) && (scr_status&0x0040))
+		kgdbsci_rx_interrupt(irq, ptr, regs);
 
-        kgdb_put_char(kgdb_sci_port, c);
+	return IRQ_HANDLED;
 }
 
-/* Clear any errors on the SCI */
-static void kgdb_handle_error(struct sci_port *port)
+static void __init kgdbsci_lateinit(void)
 {
-        sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));  /* Clear error flags */
+	if (KGDBPORT.irqs[0] == KGDBPORT.irqs[1]) {
+		if (!KGDBPORT.irqs[0]) {
+			printk(KERN_ERR "kgdbsci: Cannot allocate irq.\n");
+			return;
+		}
+		if (request_irq(KGDBPORT.irqs[0], kgdbsci_mpxed_interrupt,
+					SA_INTERRUPT, "kgdbsci",
+					&KGDBPORT.port)) {
+			printk(KERN_ERR "kgdbsci: Cannot allocate irq.\n");
+			return;
+		}
+	} else {
+		if (KGDBPORT.irqs[1])
+			request_irq(KGDBPORT.irqs[1],
+					kgdbsci_rx_interrupt, SA_INTERRUPT,
+					"kgdbsci", &KGDBPORT.port);
+	}
 }
+#endif
 
-/* Breakpoint if there's a break sent on the serial port */
-static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs)
+/*
+ * We use the normal init routine to setup the port, so we can't be
+ * in here too early.
+ */
+static int kgdbsci_init(void)
 {
-        struct sci_port *port = ptr;
-        unsigned short status = sci_in(port, SCxSR);
+	struct termios termios;
 
-        if (status & SCxSR_BRK(port)) {
+	memset(&termios, 0, sizeof(struct termios));
 
-                /* Break into the debugger if a break is detected */
-                BREAKPOINT();
+	termios.c_cflag = CREAD | HUPCL | CLOCAL | CS8;
+	switch (kgdbsci_baud) {
+	case 9600:
+		termios.c_cflag |= B9600;
+		break;
+	case 19200:
+		termios.c_cflag |= B19200;
+		break;
+	case 38400:
+		termios.c_cflag |= B38400;
+		break;
+	case 57600:
+		termios.c_cflag |= B57600;
+		break;
+	case 115200:
+		termios.c_cflag |= B115200;
+		break;
+	}
+	sci_set_termios(&KGDBPORT.port, &termios, NULL);
 
-                /* Clear */
-                sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
-        }
+	return 0;
 }
 
-#endif /* CONFIG_SH_KGDB */
+struct kgdb_io kgdb_io_ops = {
+	.read_char = kgdbsci_read_char,
+	.write_char = kgdbsci_write_char,
+	.init = kgdbsci_init,
+#ifndef CONFIG_SERIAL_SH_SCI_CONSOLE
+	.late_init = kgdbsci_lateinit,
+#else /* ! CONFIG_SERIAL_SH_SCI_CONSOLE */
+	.late_init = NULL,
+#endif /* ! CONFIG_SERIAL_SH_SCI_CONSOLE */
+	.pre_exception = NULL,
+	.post_exception = NULL
+};
+
+/*
+ * Syntax for this cmdline option is "kgdbsci=ttyno,baudrate".
+ */
+static int __init
+kgdbsci_opt(char *str)
+{
+	/* We might have anywhere from 1 to 3 ports. */
+	if (*str < '0' || *str > SCI_NPORTS + '0')
+		 goto errout;
+	kgdbsci_ttySC = *str - '0';
+	str++;
+	if (*str != ',')
+		 goto errout;
+	str++;
+	kgdbsci_baud = simple_strtoul(str, &str, 10);
+	if (kgdbsci_baud != 9600 && kgdbsci_baud != 19200 &&
+	    kgdbsci_baud != 38400 && kgdbsci_baud != 57600 &&
+	    kgdbsci_baud != 115200)
+		 goto errout;
+
+	return 0;
+
+errout:
+	printk(KERN_ERR "Invalid syntax for option kgdbsci=\n");
+	return 1;
+}
+__setup("kgdbsci", kgdbsci_opt);
+#endif /* CONFIG_KGDB_SH_SCI */
 
 #if defined(__H8300S__)
 enum { sci_disable, sci_enable };
@@ -541,6 +594,16 @@ static inline void sci_receive_chars(str
 					continue;
 				}
 
+#ifdef CONFIG_KGDB_SH_SCI
+				/* We assume that a ^C on the port KGDB
+				 * is using means that KGDB wants to
+				 * interrupt the running system.
+				 */
+				if (port->line == KGDBPORT.port.line &&
+						c == 3)
+					breakpoint();
+#endif
+
 				/* Store data and status */
 				tty->flip.char_buf_ptr[i] = c;
 				if (status&SCxSR_FER(port)) {
@@ -1552,6 +1615,7 @@ static int __init sci_console_init(void)
 console_initcall(sci_console_init);
 #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
 
+#if 0
 #ifdef CONFIG_SH_KGDB
 /*
  * FIXME: Most of this can go away.. at the moment, we rely on
@@ -1597,30 +1661,9 @@ int __init kgdb_console_setup(struct con
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
 #endif /* CONFIG_SH_KGDB */
+#endif /* 0 */
 
-#ifdef CONFIG_SH_KGDB_CONSOLE
-static struct console kgdb_console = {
-        .name		= "ttySC",
-        .write		= kgdb_console_write,
-        .setup		= kgdb_console_setup,
-        .flags		= CON_PRINTBUFFER | CON_ENABLED,
-        .index		= -1,
-	.data		= &sci_uart_driver,
-};
-
-/* Register the KGDB console so we get messages (d'oh!) */
-static int __init kgdb_console_init(void)
-{
-	register_console(&kgdb_console);
-	return 0;
-}
-
-console_initcall(kgdb_console_init);
-#endif /* CONFIG_SH_KGDB_CONSOLE */
-
-#if defined(CONFIG_SH_KGDB_CONSOLE)
-#define SCI_CONSOLE	&kgdb_console
-#elif defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 #define SCI_CONSOLE	&serial_console
 #else
 #define SCI_CONSOLE 	0
@@ -1689,4 +1732,3 @@ static void __exit sci_exit(void)
 
 module_init(sci_init);
 module_exit(sci_exit);
-
Index: linux-2.6.14/include/asm-sh/kgdb.h
===================================================================
--- linux-2.6.14.orig/include/asm-sh/kgdb.h
+++ linux-2.6.14/include/asm-sh/kgdb.h
@@ -2,94 +2,39 @@
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  *
- * Based on original code by Glenn Engel, Jim Kingdon,
- * David Grothe <[email protected]>, Tigran Aivazian, <[email protected]> and
- * Amit S. Kale <[email protected]>
- * 
- * Super-H port based on sh-stub.c (Ben Lee and Steve Chamberlain) by
- * Henry Bell <[email protected]>
- * 
- * Header file for low-level support for remote debug using GDB. 
+ * Based on a file that was modified or based on files by: Glenn Engel,
+ * Jim Kingdon, David Grothe <[email protected]>, Tigran Aivazian <[email protected]>,
+ * Amit S. Kale <[email protected]>, sh-stub.c from Ben Lee and
+ * Steve Chamberlain, Henry Bell <[email protected]>
+ *
+ * Maintainer: Tom Rini <[email protected]>
  *
  */
 
 #ifndef __KGDB_H
 #define __KGDB_H
 
-#include <asm/ptrace.h>
-
-struct console;
+/* Based on sh-gdb.c from gdb-6.1, Glenn
+     Engel at HP  Ben Lee and Steve Chamberlain */
+#define NUMREGBYTES	112	/* 92 */
+#define NUMCRITREGBYTES	(9 << 2)
+#define BUFMAX		400
 
-/* Same as pt_regs but has vbr in place of syscall_nr */
+#ifndef __ASSEMBLY__
 struct kgdb_regs {
         unsigned long regs[16];
         unsigned long pc;
         unsigned long pr;
-        unsigned long sr;
         unsigned long gbr;
+        unsigned long vbr;
         unsigned long mach;
         unsigned long macl;
-        unsigned long vbr;
-};
-
-/* State info */
-extern char kgdb_in_gdb_mode;
-extern int kgdb_done_init;
-extern int kgdb_enabled;
-extern int kgdb_nofault;	/* Ignore bus errors (in gdb mem access) */
-extern int kgdb_halt;		/* Execute initial breakpoint at startup */
-extern char in_nmi;		/* Debounce flag to prevent NMI reentry*/
-
-/* SCI */
-extern int kgdb_portnum;
-extern int kgdb_baud;
-extern char kgdb_parity;
-extern char kgdb_bits;
-extern int kgdb_console_setup(struct console *, char *);
-
-/* Init and interface stuff */
-extern int kgdb_init(void);
-extern int (*kgdb_serial_setup)(void);
-extern int (*kgdb_getchar)(void);
-extern void (*kgdb_putchar)(int);
-
-struct kgdb_sermap {
-	char *name;
-	int namelen;
-	int (*setup_fn)(struct console *, char *);
-	struct kgdb_sermap *next;
+        unsigned long sr;
 };
-extern void kgdb_register_sermap(struct kgdb_sermap *map);
-extern struct kgdb_sermap *kgdb_porttype;
 
-/* Trap functions */
-typedef void (kgdb_debug_hook_t)(struct pt_regs *regs); 
-typedef void (kgdb_bus_error_hook_t)(void);
-extern kgdb_debug_hook_t  *kgdb_debug_hook;
-extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
-
-extern void breakpoint(void);
-
-/* Console */
-struct console;
-void kgdb_console_write(struct console *co, const char *s, unsigned count);
-void kgdb_console_init(void);
-
-/* Prototypes for jmp fns */
-#define _JBLEN 9
-typedef        int jmp_buf[_JBLEN];
-extern void    longjmp(jmp_buf __jmpb, int __retval);
-extern int     setjmp(jmp_buf __jmpb);
-
-/* Variadic macro to print our own message to the console */
-#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__)
-
-/* Forced breakpoint */
-#define BREAKPOINT() do {                                     \
-  if (kgdb_enabled) {                                         \
-    asm volatile("trapa   #0xff");                            \
-  }                                                           \
-} while (0)
+#define BREAKPOINT()		asm("trapa #0xff");
+#define BREAK_INSTR_SIZE	2
+#define CACHE_FLUSH_IS_SAFE	1
 
 /* KGDB should be able to flush all kernel text space */
 #if defined(CONFIG_CPU_SH4)
@@ -102,30 +47,5 @@ extern int     setjmp(jmp_buf __jmpb);
 #else
 #define kgdb_flush_icache_range(start, end)	do { } while (0)
 #endif
-
-/* Kernel assert macros */
-#ifdef CONFIG_KGDB_KERNEL_ASSERTS
-
-/* Predefined conditions */
-#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
-#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
-#define KA_VALID_KPTR(ptr)  (!(ptr) || \
-              ((void *)(ptr) >= (void *)PAGE_OFFSET &&  \
-               (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
-#define KA_VALID_PTRORERR(errptr) \
-               (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
-#define KA_HELD_GKL()  (current->lock_depth >= 0)
-
-/* The actual assert */
-#define KGDB_ASSERT(condition, message) do {                   \
-       if (!(condition) && (kgdb_enabled)) {                   \
-               KGDB_PRINTK("Assertion failed at %s:%d: %s\n",  \
-                                  __FILE__, __LINE__, message);\
-               BREAKPOINT();                                   \
-       }                                                       \
-} while (0)
-#else
-#define KGDB_ASSERT(condition, message)
-#endif
-
+#endif				/* !__ASSEMBLY__ */
 #endif
Index: linux-2.6.14/include/asm-sh/system.h
===================================================================
--- linux-2.6.14.orig/include/asm-sh/system.h
+++ linux-2.6.14/include/asm-sh/system.h
@@ -7,6 +7,7 @@
  */
 
 #include <linux/config.h>
+#include <asm/types.h>
 
 /*
  *	switch_to() should switch tasks to task nr n, first
@@ -252,6 +253,45 @@ static __inline__ unsigned long __xchg(u
 	return x;
 }
 
+static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
+	unsigned long new)
+{
+	__u32 retval;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	retval = *m;
+	if (retval == old)
+		*m = new;
+	local_irq_restore(flags);       /* implies memory barrier  */
+	return retval;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg(). */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+#define __HAVE_ARCH_CMPXCHG	1
+
+static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
+		unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
 /* XXX
  * disable hlt during certain critical i/o operations
  */
Index: linux-2.6.14/lib/Kconfig.debug
===================================================================
--- linux-2.6.14.orig/lib/Kconfig.debug
+++ linux-2.6.14/lib/Kconfig.debug
@@ -170,7 +170,7 @@ config DEBUG_FS
 
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
-	depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML)
+	depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || SUPERH)
 	default y if DEBUG_INFO && UML
 	help
 	  If you say Y here the resulting kernel image will be slightly larger
@@ -181,13 +181,13 @@ config FRAME_POINTER
 config WANT_EXTRA_DEBUG_INFORMATION
 	bool
 	select DEBUG_INFO
-	select FRAME_POINTER if X86
+	select FRAME_POINTER if X86 || SUPERH
 	default n
 
 config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
-	depends on DEBUG_KERNEL && (X86 || MIPS || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
+	depends on DEBUG_KERNEL && (X86 || MIPS || (SUPERH && !SUPERH64) || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32))
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb. It is strongly suggested that you enable

-- 
Tom
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux