All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jason Wessel <jason.wessel@windriver.com>
To: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.arm.linux.org.uk
Subject: [PATCH 14/21] KGDB: KGDB arch support for ARM
Date: Mon, 15 Oct 2007 13:33:37 -0500	[thread overview]
Message-ID: <4713B281.8090702@windriver.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 57 bytes --]

Signed-off-by: Jason Wessel <jason.wessel@windriver.com>

[-- Attachment #2: arm-lite.patch --]
[-- Type: text/x-patch, Size: 28715 bytes --]

arm-lite.patch

From: Jason Wessel <jason.wessel@windriver.com>
CC: linux-arm-kernel@lists.arm.linux.org.uk
Subject: [PATCH] KGDB arch support for ARM

This adds a backend, written by Deepak Saxena <dsaxena@plexity.net>
and George Davis <gdavis@mvista.com> as well as support for the TI
OMAP boards, ADI Coyote, PXA2xx, ARM Versatile and PNX4008.  Geoff
Levand <geoffrey.levand@am.sony.com>, Nicolas Pitre, and Manish
Lachwani have contributed various fixups here as well.  This should
only require (on boards that don't have a custom uart) registering the
uart with KGDB to add any other boards, or using kgdboe it should Just
Work.

Signed-off-by: Milind Dumbare <milind@linsyssoft.com>
Signed-off-by: Dmitry Antipov <antipov@ru.mvista.com>
Signed-off-by: Tom Rini <trini@kernel.crashing.org>
Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
Signed-off-by: Vitaly Wool <vwool@ru.mvista.com>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
---
 arch/arm/kernel/Makefile             |    1 
 arch/arm/kernel/kgdb-jmp.S           |   32 +++++
 arch/arm/kernel/kgdb.c               |  207 +++++++++++++++++++++++++++++++++++
 arch/arm/kernel/setup.c              |    5 
 arch/arm/kernel/traps.c              |   11 +
 arch/arm/mach-ixp2000/core.c         |    4 
 arch/arm/mach-ixp2000/ixdp2x01.c     |    6 +
 arch/arm/mach-ixp4xx/coyote-setup.c  |    4 
 arch/arm/mach-ixp4xx/ixdp425-setup.c |   21 ++-
 arch/arm/mach-omap1/serial.c         |    4 
 arch/arm/mach-pnx4008/core.c         |    4 
 arch/arm/mach-pxa/Makefile           |    1 
 arch/arm/mach-pxa/kgdb-serial.c      |   97 ++++++++++++++++
 arch/arm/mach-versatile/core.c       |    8 +
 arch/arm/mm/extable.c                |    7 +
 drivers/serial/Makefile              |    1 
 drivers/serial/amba-pl011.c          |    3 
 drivers/serial/pl011_kgdb.c          |  117 +++++++++++++++++++
 drivers/serial/pxa.c                 |    5 
 include/asm-arm/kgdb.h               |  103 +++++++++++++++++
 lib/Kconfig.kgdb                     |   55 ++++++++-
 21 files changed, 689 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm/kernel/kgdb-jmp.S
 create mode 100644 arch/arm/kernel/kgdb.c
 create mode 100644 arch/arm/mach-pxa/kgdb-serial.c
 create mode 100644 drivers/serial/pl011_kgdb.c
 create mode 100644 include/asm-arm/kgdb.h

--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PCI)		+= bios32.o isa.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
+obj-$(CONFIG_KGDB)		+= kgdb.o kgdb-jmp.o
 
 obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o		:= -Wa,-mcpu=ep9312
--- /dev/null
+++ b/arch/arm/kernel/kgdb-jmp.S
@@ -0,0 +1,32 @@
+/*
+ * arch/arm/kernel/kgdb-jmp.S
+ *
+ * Trivial setjmp and longjmp procedures to support bus error recovery
+ * which may occur during kgdb memory read/write operations.
+ *
+ * Author: MontaVista Software, Inc. <source@mvista.com>
+ *         source@mvista.com
+ *
+ * 2002-2005 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2. This program as licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+#include <linux/linkage.h>
+
+ENTRY (kgdb_fault_setjmp)
+	/* Save registers */
+	stmia	r0, {r0-r14}
+	str	lr,[r0, #60]
+	mrs	r1,cpsr
+	str	r1,[r0,#64]
+	ldr	r1,[r0,#4]
+	mov	r0, #0
+	mov	pc,lr
+
+ENTRY (kgdb_fault_longjmp)
+	/* Restore registers */
+	mov	r1,#1
+	str	r1,[r0]
+	ldr     r1,[r0, #64]
+	msr     spsr,r1
+	ldmia	r0,{r0-pc}^
--- /dev/null
+++ b/arch/arm/kernel/kgdb.c
@@ -0,0 +1,207 @@
+/*
+ * arch/arm/kernel/kgdb.c
+ *
+ * ARM KGDB support
+ *
+ * Copyright (c) 2002-2004 MontaVista Software, Inc
+ *
+ * Authors:  George Davis <davis_g@mvista.com>
+ *           Deepak Saxena <dsaxena@plexity.net>
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/personality.h>
+#include <linux/ptrace.h>
+#include <linux/elf.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/unistd.h>
+
+#include <asm/atomic.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+
+/* Make a local copy of the registers passed into the handler (bletch) */
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
+{
+	int regno;
+
+	/* Initialize all to zero (??) */
+	for (regno = 0; regno < GDB_MAX_REGS; regno++)
+		gdb_regs[regno] = 0;
+
+	gdb_regs[_R0] = kernel_regs->ARM_r0;
+	gdb_regs[_R1] = kernel_regs->ARM_r1;
+	gdb_regs[_R2] = kernel_regs->ARM_r2;
+	gdb_regs[_R3] = kernel_regs->ARM_r3;
+	gdb_regs[_R4] = kernel_regs->ARM_r4;
+	gdb_regs[_R5] = kernel_regs->ARM_r5;
+	gdb_regs[_R6] = kernel_regs->ARM_r6;
+	gdb_regs[_R7] = kernel_regs->ARM_r7;
+	gdb_regs[_R8] = kernel_regs->ARM_r8;
+	gdb_regs[_R9] = kernel_regs->ARM_r9;
+	gdb_regs[_R10] = kernel_regs->ARM_r10;
+	gdb_regs[_FP] = kernel_regs->ARM_fp;
+	gdb_regs[_IP] = kernel_regs->ARM_ip;
+	gdb_regs[_SP] = kernel_regs->ARM_sp;
+	gdb_regs[_LR] = kernel_regs->ARM_lr;
+	gdb_regs[_PC] = kernel_regs->ARM_pc;
+	gdb_regs[_CPSR] = kernel_regs->ARM_cpsr;
+}
+
+/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
+{
+	kernel_regs->ARM_r0 = gdb_regs[_R0];
+	kernel_regs->ARM_r1 = gdb_regs[_R1];
+	kernel_regs->ARM_r2 = gdb_regs[_R2];
+	kernel_regs->ARM_r3 = gdb_regs[_R3];
+	kernel_regs->ARM_r4 = gdb_regs[_R4];
+	kernel_regs->ARM_r5 = gdb_regs[_R5];
+	kernel_regs->ARM_r6 = gdb_regs[_R6];
+	kernel_regs->ARM_r7 = gdb_regs[_R7];
+	kernel_regs->ARM_r8 = gdb_regs[_R8];
+	kernel_regs->ARM_r9 = gdb_regs[_R9];
+	kernel_regs->ARM_r10 = gdb_regs[_R10];
+	kernel_regs->ARM_fp = gdb_regs[_FP];
+	kernel_regs->ARM_ip = gdb_regs[_IP];
+	kernel_regs->ARM_sp = gdb_regs[_SP];
+	kernel_regs->ARM_lr = gdb_regs[_LR];
+	kernel_regs->ARM_pc = gdb_regs[_PC];
+	kernel_regs->ARM_cpsr = gdb_regs[_CPSR];
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
+				 struct task_struct *task)
+{
+	int regno;
+	struct pt_regs *thread_regs;
+
+	/* Just making sure... */
+	if (task == NULL)
+		return;
+
+	/* Initialize to zero */
+	for (regno = 0; regno < GDB_MAX_REGS; regno++)
+		gdb_regs[regno] = 0;
+
+	/* Otherwise, we have only some registers from switch_to() */
+	thread_regs = task_pt_regs(task);
+	gdb_regs[_R0] = thread_regs->ARM_r0;	/* Not really valid? */
+	gdb_regs[_R1] = thread_regs->ARM_r1;	/* "               " */
+	gdb_regs[_R2] = thread_regs->ARM_r2;	/* "               " */
+	gdb_regs[_R3] = thread_regs->ARM_r3;	/* "               " */
+	gdb_regs[_R4] = thread_regs->ARM_r4;
+	gdb_regs[_R5] = thread_regs->ARM_r5;
+	gdb_regs[_R6] = thread_regs->ARM_r6;
+	gdb_regs[_R7] = thread_regs->ARM_r7;
+	gdb_regs[_R8] = thread_regs->ARM_r8;
+	gdb_regs[_R9] = thread_regs->ARM_r9;
+	gdb_regs[_R10] = thread_regs->ARM_r10;
+	gdb_regs[_FP] = thread_regs->ARM_fp;
+	gdb_regs[_IP] = thread_regs->ARM_ip;
+	gdb_regs[_SP] = thread_regs->ARM_sp;
+	gdb_regs[_LR] = thread_regs->ARM_lr;
+	gdb_regs[_PC] = thread_regs->ARM_pc;
+	gdb_regs[_CPSR] = thread_regs->ARM_cpsr;
+}
+
+static int compiled_break;
+
+int kgdb_arch_handle_exception(int exception_vector, int signo,
+			       int err_code, char *remcom_in_buffer,
+			       char *remcom_out_buffer,
+			       struct pt_regs *linux_regs)
+{
+	long addr;
+	char *ptr;
+
+	switch (remcom_in_buffer[0]) {
+	case 'D':
+	case 'k':
+	case 'c':
+		kgdb_contthread = NULL;
+
+		/*
+		 * Try to read optional parameter, pc unchanged if no parm.
+		 * If this was a compiled breakpoint, we need to move
+		 * to the next instruction or we will just breakpoint
+		 * over and over again.
+		 */
+		ptr = &remcom_in_buffer[1];
+		if (kgdb_hex2long(&ptr, &addr)) {
+			linux_regs->ARM_pc = addr;
+		} else if (compiled_break == 1) {
+			linux_regs->ARM_pc += 4;
+		}
+
+		compiled_break = 0;
+
+		return 0;
+	}
+
+	return -1;
+}
+
+static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
+{
+	if (!kgdb_io_ops.read_char)
+		return 1;
+
+	kgdb_handle_exception(1, SIGTRAP, 0, regs);
+
+	return 0;
+}
+
+static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
+{
+	if (!kgdb_io_ops.read_char)
+		return 1;
+
+	compiled_break = 1;
+	kgdb_handle_exception(1, SIGTRAP, 0, regs);
+
+	return 0;
+}
+
+static struct undef_hook kgdb_brkpt_hook = {
+	.instr_mask = 0xffffffff,
+	.instr_val = KGDB_BREAKINST,
+	.fn = kgdb_brk_fn
+};
+
+static struct undef_hook kgdb_compiled_brkpt_hook = {
+	.instr_mask = 0xffffffff,
+	.instr_val = KGDB_COMPILED_BREAK,
+	.fn = kgdb_compiled_brk_fn
+};
+
+/*
+ * Register our undef instruction hooks with ARM undef core.
+ * We regsiter a hook specifically looking for the KGB break inst
+ * and we handle the normal undef case within the do_undefinstr
+ * handler.
+ */
+int kgdb_arch_init(void)
+{
+	register_undef_hook(&kgdb_brkpt_hook);
+	register_undef_hook(&kgdb_compiled_brkpt_hook);
+
+	return 0;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+#ifndef __ARMEB__
+	.gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}
+#else /* ! __ARMEB__ */
+	.gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe}
+#endif
+};
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -837,6 +837,11 @@ void __init setup_arch(char **cmdline_p)
 	conswitchp = &dummy_con;
 #endif
 #endif
+
+#if	defined(CONFIG_KGDB)
+	extern void __init early_trap_init(void);
+	early_trap_init();
+#endif
 }
 
 
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -302,6 +302,7 @@ asmlinkage void __exception do_undefinst
 	unsigned int instr;
 	struct undef_hook *hook;
 	siginfo_t info;
+	mm_segment_t fs;
 	void __user *pc;
 	unsigned long flags;
 
@@ -312,6 +313,8 @@ asmlinkage void __exception do_undefinst
 	 */
 	regs->ARM_pc -= correction;
 
+	fs = get_fs();
+	set_fs(KERNEL_DS);
 	pc = (void __user *)instruction_pointer(regs);
 
 	if (processor_mode(regs) == SVC_MODE) {
@@ -321,6 +324,7 @@ asmlinkage void __exception do_undefinst
 	} else {
 		get_user(instr, (u32 __user *)pc);
 	}
+	set_fs(fs);
 
 	spin_lock_irqsave(&undef_lock, flags);
 	list_for_each_entry(hook, &undef_hook, node) {
@@ -706,6 +710,13 @@ EXPORT_SYMBOL(abort);
 
 void __init trap_init(void)
 {
+#if   defined(CONFIG_KGDB)
+	return;
+}
+
+void __init early_trap_init(void)
+{
+#endif
 	unsigned long vectors = CONFIG_VECTORS_BASE;
 	extern char __stubs_start[], __stubs_end[];
 	extern char __vectors_start[], __vectors_end[];
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -25,6 +25,7 @@
 #include <linux/bitops.h>
 #include <linux/serial_8250.h>
 #include <linux/mm.h>
+#include <linux/kgdb.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -184,6 +185,9 @@ static struct platform_device ixp2000_se
 void __init ixp2000_uart_init(void)
 {
 	platform_device_register(&ixp2000_serial_device);
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_platform_port(0, &ixp2000_serial_port);
+#endif
 }
 
 
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -30,6 +30,7 @@
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/kgdb.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -413,6 +414,11 @@ static void __init ixdp2x01_init_machine
 	platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices));
 	ixp2000_uart_init();
 	ixdp2x01_uart_init();
+
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_platform_port(0, ixdp2x01_serial_port1);
+	kgdb8250_add_platform_port(1, ixdp2x01_serial_port1);
+#endif
 }
 
 
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -96,6 +96,10 @@ static void __init coyote_init(void)
 	}
 
 	platform_add_devices(coyote_devices, ARRAY_SIZE(coyote_devices));
+
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_platform_port(0, &coyote_uart_data);
+#endif
 }
 
 #ifdef CONFIG_ARCH_ADI_COYOTE
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -14,6 +14,7 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/serial_8250.h>
+#include <linux/kgdb.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
@@ -152,7 +153,8 @@ static struct plat_serial8250_port ixdp4
 		.mapbase	= IXP4XX_UART1_BASE_PHYS,
 		.membase	= (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
 		.irq		= IRQ_IXP4XX_UART1,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+					UPF_SHARE_IRQ,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= IXP4XX_UART_XTAL,
@@ -161,7 +163,8 @@ static struct plat_serial8250_port ixdp4
 		.mapbase	= IXP4XX_UART2_BASE_PHYS,
 		.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
 		.irq		= IRQ_IXP4XX_UART2,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+					UPF_SHARE_IRQ,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.uartclk	= IXP4XX_UART_XTAL,
@@ -219,12 +222,22 @@ static void __init ixdp425_init(void)
 	platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices));
 }
 
+static void __init ixdp425_map_io(void)
+{
+	ixp4xx_map_io();
+
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_platform_port(0, &ixdp425_uart_data[0]);
+	kgdb8250_add_platform_port(1, &ixdp425_uart_data[1]);
+#endif
+}
+
 #ifdef CONFIG_ARCH_IXDP425
 MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
-	.map_io		= ixp4xx_map_io,
+	.map_io		= ixdp425_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.boot_params	= 0x0100,
@@ -237,7 +250,7 @@ MACHINE_START(IXDP465, "Intel IXDP465 De
 	/* Maintainer: MontaVista Software, Inc. */
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
-	.map_io		= ixp4xx_map_io,
+	.map_io		= ixdp425_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
 	.boot_params	= 0x0100,
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/serial.h>
 #include <linux/tty.h>
+#include <linux/kgdb.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
@@ -199,6 +200,9 @@ void __init omap_serial_init(void)
 			break;
 		}
 		omap_serial_reset(&serial_platform_data[i]);
+#ifdef CONFIG_KGDB_8250
+		kgdb8250_add_platform_port(i, &serial_platform_data[i]);
+#endif
 	}
 }
 
--- a/arch/arm/mach-pnx4008/core.c
+++ b/arch/arm/mach-pnx4008/core.c
@@ -224,6 +224,10 @@ static void __init pnx4008_init(void)
 	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
 	/* Switch on the UART clocks */
 	pnx4008_uart_init();
+#ifdef CONFIG_KGDB_8250
+	kgdb8250_add_platform_port(0, &platform_serial_ports[0]);
+	kgdb8250_add_platform_port(1, &platform_serial_ports[1]);
+#endif
 }
 
 static struct map_desc pnx4008_io_desc[] __initdata = {
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_LEDS) += $(led-y)
 # Misc features
 obj-$(CONFIG_PM) += pm.o sleep.o
 obj-$(CONFIG_PXA_SSP) += ssp.o
+obj-$(CONFIG_KGDB_PXA_SERIAL) += kgdb-serial.o
 
 ifeq ($(CONFIG_PXA27x),y)
 obj-$(CONFIG_PM) += standby.o
--- /dev/null
+++ b/arch/arm/mach-pxa/kgdb-serial.c
@@ -0,0 +1,97 @@
+/*
+ * linux/arch/arm/mach-pxa/kgdb-serial.c
+ *
+ * Provides low level kgdb serial support hooks for PXA2xx boards
+ *
+ * Author:	Nicolas Pitre
+ * Copyright:	(C) 2002-2005 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/kgdb.h>
+#include <asm/processor.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#if   defined(CONFIG_KGDB_PXA_FFUART)
+
+#define UART		FFUART
+#define CKEN_UART	CKEN6_FFUART
+#define GPIO_RX_MD	GPIO34_FFRXD_MD
+#define GPIO_TX_MD	GPIO39_FFTXD_MD
+
+#elif defined(CONFIG_KGDB_PXA_BTUART)
+
+#define UART		BTUART
+#define CKEN_UART	CKEN7_BTUART
+#define GPIO_RX_MD	GPIO42_BTRXD_MD
+#define GPIO_TX_MD	GPIO43_BTTXD_MD
+
+#elif defined(CONFIG_KGDB_PXA_STUART)
+
+#define UART		STUART
+#define CKEN_UART	CKEN5_STUART
+#define GPIO_RX_MD	GPIO46_STRXD_MD
+#define GPIO_TX_MD	GPIO47_STTXD_MD
+
+#endif
+
+#define UART_BAUDRATE	(CONFIG_KGDB_BAUDRATE)
+
+static volatile unsigned long *port = (unsigned long *)&UART;
+
+static int kgdb_serial_init(void)
+{
+	pxa_set_cken(CKEN_UART, 1);
+	pxa_gpio_mode(GPIO_RX_MD);
+	pxa_gpio_mode(GPIO_TX_MD);
+
+	port[UART_IER] = 0;
+	port[UART_LCR] = LCR_DLAB;
+	port[UART_DLL] = ((921600 / UART_BAUDRATE) & 0xff);
+	port[UART_DLM] = ((921600 / UART_BAUDRATE) >> 8);
+	port[UART_LCR] = LCR_WLS1 | LCR_WLS0;
+	port[UART_MCR] = 0;
+	port[UART_IER] = IER_UUE;
+	port[UART_FCR] = FCR_ITL_16;
+
+	return 0;
+}
+
+static void kgdb_serial_putchar(u8 c)
+{
+	if (!(CKEN & CKEN_UART) || port[UART_IER] != IER_UUE)
+		kgdb_serial_init();
+	while (!(port[UART_LSR] & LSR_TDRQ))
+		cpu_relax();
+	port[UART_TX] = c;
+}
+
+static void kgdb_serial_flush(void)
+{
+	if ((CKEN & CKEN_UART) && (port[UART_IER] & IER_UUE))
+		while (!(port[UART_LSR] & LSR_TEMT))
+			cpu_relax();
+}
+
+static int kgdb_serial_getchar(void)
+{
+	unsigned char c;
+	if (!(CKEN & CKEN_UART) || port[UART_IER] != IER_UUE)
+		kgdb_serial_init();
+	while (!(port[UART_LSR] & UART_LSR_DR))
+		cpu_relax();
+	c = port[UART_RX];
+	return c;
+}
+
+struct kgdb_io kgdb_io_ops = {
+	.init = kgdb_serial_init,
+	.write_char = kgdb_serial_putchar,
+	.flush = kgdb_serial_flush,
+	.read_char = kgdb_serial_getchar,
+};
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -184,6 +184,14 @@ static struct map_desc versatile_io_desc
 		.type		= MT_DEVICE
 	},
 #endif
+#ifdef CONFIG_KGDB_AMBA_PL011
+	{
+		.virtual	=  IO_ADDRESS(CONFIG_KGDB_AMBA_BASE),
+		.pfn		= __phys_to_pfn(CONFIG_KGDB_AMBA_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE
+	},
+#endif
 #ifdef CONFIG_PCI
  	{
 		.virtual	=  IO_ADDRESS(VERSATILE_PCI_CORE_BASE),
--- a/arch/arm/mm/extable.c
+++ b/arch/arm/mm/extable.c
@@ -2,6 +2,7 @@
  *  linux/arch/arm/mm/extable.c
  */
 #include <linux/module.h>
+#include <linux/kgdb.h>
 #include <asm/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
@@ -11,6 +12,12 @@ int fixup_exception(struct pt_regs *regs
 	fixup = search_exception_tables(instruction_pointer(regs));
 	if (fixup)
 		regs->ARM_pc = fixup->fixup;
+#ifdef CONFIG_KGDB
+	if (atomic_read(&debugger_active) && kgdb_may_fault)
+		/* Restore our previous state. */
+		kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+		/* Not reached. */
+#endif
 
 	return fixup != NULL;
 }
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mc
 obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o
 obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
 obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
+obj-$(CONFIG_KGDB_AMBA_PL011)	+= pl011_kgdb.o
 obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
 obj-$(CONFIG_SERIAL_PXA) += pxa.o
 obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -332,7 +332,8 @@ static int pl011_startup(struct uart_por
 	/*
 	 * Allocate the IRQ
 	 */
-	retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+	retval = request_irq(uap->port.irq, pl011_int, IRQF_SHARED,
+			 "uart-pl011", uap);
 	if (retval)
 		goto clk_dis;
 
--- /dev/null
+++ b/drivers/serial/pl011_kgdb.c
@@ -0,0 +1,117 @@
+/*
+ * driver/serial/pl011_kgdb.c
+ *
+ * Support for KGDB on ARM AMBA PL011 UARTs
+ *
+ * Authors: Manish Lachwani <mlachwani@mvista.com>
+ *          Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (c) 2005-2007 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 expressor implied.
+ *
+ */
+#include <linux/kgdb.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
+#include <linux/io.h>
+
+#include <asm/processor.h>
+#include <asm/hardware.h>
+
+static int kgdb_irq = CONFIG_KGDB_AMBA_IRQ;
+
+#define UART_DIVISOR	(CONFIG_KGDB_AMBA_UARTCLK * 4 / CONFIG_KGDB_BAUDRATE)
+/*
+ * Todo: IO_ADDRESS is not very generic across ARM...
+ */
+static volatile unsigned char *kgdb_port =
+	(unsigned char *)IO_ADDRESS(CONFIG_KGDB_AMBA_BASE);
+
+/*
+ * Init code taken from amba-pl011.c.
+ */
+static int kgdb_serial_init(void)
+{
+	writew(0, kgdb_port + UART010_CR);
+
+	/* Set baud rate */
+	writew(UART_DIVISOR & 0x3f, kgdb_port + UART011_FBRD);
+	writew(UART_DIVISOR >> 6, kgdb_port + UART011_IBRD);
+
+	writew(UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN, kgdb_port +
+		UART010_LCRH);
+	writew(UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_RXE,
+	       kgdb_port + UART010_CR);
+
+	writew(UART011_RXIM, kgdb_port + UART011_IMSC);
+
+	return 0;
+}
+
+static void kgdb_serial_putchar(u8 ch)
+{
+	unsigned int status;
+
+	do {
+		status = readw(kgdb_port + UART01x_FR);
+	} while (status & UART01x_FR_TXFF);
+
+	writew(ch, kgdb_port + UART01x_DR);
+}
+
+static int kgdb_serial_getchar(void)
+{
+	unsigned int status;
+	int ch;
+
+#ifdef CONFIG_DEBUG_LL_OLD
+	printascii("Entering serial_getchar loop");
+#endif
+	do {
+		status = readw(kgdb_port + UART01x_FR);
+	} while (status & UART01x_FR_RXFE);
+	ch = readw(kgdb_port + UART01x_DR);
+#ifdef CONFIG_DEBUG_LL_OLD
+	printascii("Exited serial_getchar loop");
+	printascii("Read char: ");
+	printch(ch);
+	printascii("\n");
+#endif
+	return ch;
+}
+
+static irqreturn_t kgdb_interrupt(int irq, void *dev_id)
+{
+	int status = readw(kgdb_port + UART011_MIS);
+
+#ifdef CONFIG_DEBUG_LL_OLD
+	printascii("KGDB irq\n");
+#endif
+	if (irq != kgdb_irq)
+		return IRQ_NONE;
+
+	if (status & 0x40)
+		breakpoint();
+
+	return IRQ_HANDLED;
+}
+
+static void __init kgdb_hookup_irq(void)
+{
+	int retval;
+	retval = request_irq(kgdb_irq, kgdb_interrupt, IRQF_SHARED,
+		"KGDB-serial", (void *)kgdb_port);
+	if (retval) {
+		printk(KERN_ERR "pl011_kgdb: ERROR requesting irq\n");
+	}
+}
+
+struct kgdb_io kgdb_io_ops = {
+	.init = kgdb_serial_init,
+	.write_char = kgdb_serial_putchar,
+	.read_char  = kgdb_serial_getchar,
+	.late_init  = kgdb_hookup_irq,
+};
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -42,6 +42,9 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/kgdb.h>
+#endif
 
 #include <asm/io.h>
 #include <asm/hardware.h>
@@ -690,6 +693,8 @@ serial_pxa_console_init(void)
 console_initcall(serial_pxa_console_init);
 
 #define PXA_CONSOLE	&serial_pxa_console
+#elif defined(CONFIG_KGDB_CONSOLE)
+#define PXA_CONSOLE	&kgdbcons
 #else
 #define PXA_CONSOLE	NULL
 #endif
--- /dev/null
+++ b/include/asm-arm/kgdb.h
@@ -0,0 +1,103 @@
+/*
+ * include/asm-arm/kgdb.h
+ *
+ * ARM KGDB support
+ *
+ * Author: Deepak Saxena <dsaxena@mvista.com>
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ *
+ */
+
+#ifndef __ASM_KGDB_H__
+#define __ASM_KGDB_H__
+
+#include <linux/ptrace.h>
+#include <asm-generic/kgdb.h>
+
+
+/*
+ * GDB assumes that we're a user process being debugged, so
+ * it will send us an SWI command to write into memory as the
+ * debug trap. When an SWI occurs, the next instruction addr is
+ * placed into R14_svc before jumping to the vector trap.
+ * This doesn't work for kernel debugging as we are already in SVC
+ * we would loose the kernel's LR, which is a bad thing. This
+ * is  bad thing.
+ *
+ * By doing this as an undefined instruction trap, we force a mode
+ * switch from SVC to UND mode, allowing us to save full kernel state.
+ *
+ * We also define a KGDB_COMPILED_BREAK which can be used to compile
+ * in breakpoints. This is important for things like sysrq-G and for
+ * the initial breakpoint from trap_init().
+ *
+ * Note to ARM HW designers: Add real trap support like SH && PPC to
+ * make our lives much much simpler. :)
+ */
+#define	BREAK_INSTR_SIZE		4
+#define GDB_BREAKINST                   0xef9f0001
+#define KGDB_BREAKINST                  0xe7ffdefe
+#define KGDB_COMPILED_BREAK             0xe7ffdeff
+#define CACHE_FLUSH_IS_SAFE		1
+
+#ifndef	__ASSEMBLY__
+
+#define	BREAKPOINT()			asm(".word 	0xe7ffdeff")
+
+
+extern void kgdb_handle_bus_error(void);
+extern int kgdb_fault_expected;
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * From Kevin Hilman:
+ *
+ * gdb is expecting the following registers layout.
+ *
+ * r0-r15: 1 long word each
+ * f0-f7:  unused, 3 long words each !!
+ * fps:    unused, 1 long word
+ * cpsr:   1 long word
+ *
+ * Even though f0-f7 and fps are not used, they need to be
+ * present in the registers sent for correct processing in
+ * the host-side gdb.
+ *
+ * In particular, it is crucial that CPSR is in the right place,
+ * otherwise gdb will not be able to correctly interpret stepping over
+ * conditional branches.
+ */
+#define _GP_REGS 		16
+#define _FP_REGS 		8
+#define _EXTRA_REGS 		2
+#define	GDB_MAX_REGS		(_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
+
+#define	KGDB_MAX_NO_CPUS	1
+#define	BUFMAX			400
+#define	NUMREGBYTES		(GDB_MAX_REGS << 2)
+#define	NUMCRITREGBYTES		(32 << 2)
+
+#define	_R0		0
+#define	_R1		1
+#define	_R2		2
+#define	_R3		3
+#define	_R4		4
+#define	_R5		5
+#define	_R6		6
+#define	_R7		7
+#define	_R8		8
+#define	_R9		9
+#define	_R10		10
+#define	_FP		11
+#define	_IP		12
+#define	_SP		13
+#define	_LR		14
+#define	_PC		15
+#define	_CPSR		(GDB_MAX_REGS - 1)
+
+/* So that we can denote the end of a frame for tracing, in the simple
+ * case. */
+#define CFI_END_FRAME(func)	__CFI_END_FRAME(_PC, _SP, func)
+
+#endif /* __ASM_KGDB_H__ */
--- a/lib/Kconfig.kgdb
+++ b/lib/Kconfig.kgdb
@@ -14,7 +14,7 @@ config KGDB
 	bool "KGDB: kernel debugging with remote gdb"
 	select WANT_EXTRA_DEBUG_INFORMATION
 	select KGDB_ARCH_HAS_SHADOW_INFO if X86_64
-	depends on DEBUG_KERNEL && (X86 || MIPS || (SUPERH && !SUPERH64) || IA64 || PPC)
+	depends on DEBUG_KERNEL && (ARM || X86 || MIPS || (SUPERH && !SUPERH64) || IA64 || PPC)
 	help
 	  If you say Y here, it will be possible to remotely debug the
 	  kernel using gdb.  Documentation of kernel debugger is available
@@ -45,6 +45,8 @@ choice
 	default KGDB_SIBYTE if SIBYTE_SB1xxx_SOC
  	default KGDB_TXX9 if CPU_TX49XX
 	default KGDB_SH_SCI if SERIAL_SH_SCI
+	default KGDB_PXA_SERIAL if ARCH_PXA
+	default KGDB_AMBA_PL011 if ARM_AMBA
 	default KGDB_8250_NOMODULE
 	help
 	  There are a number of different ways in which you can communicate
@@ -111,6 +113,34 @@ config KGDB_SH_SCI
 	depends on SUPERH && SERIAL_SH_SCI
 	help
 	  Uses the SH SCI(F) serial port to communicate with the host GDB.
+
+config KGDB_AMBA_PL011
+	bool "KGDB: On ARM AMBA PL011 Serial Port"
+	depends on ARM && ARCH_VERSATILE
+	help
+	  Enables the KGDB serial driver for the AMBA bus PL011 serial
+          devices from ARM.
+
+config KGDB_PXA_SERIAL
+	bool "KGDB: On the PXA2xx serial port"
+	depends on ARCH_PXA
+	help
+	  Enables the KGDB serial driver for Intel PXA SOC
+endchoice
+
+choice
+	prompt "PXA UART to use for KGDB"
+	depends on KGDB_PXA_SERIAL
+	default KGDB_PXA_FFUART
+
+config KGDB_PXA_FFUART
+	bool "FFUART"
+
+config KGDB_PXA_BTUART
+	bool "BTUART"
+
+config KGDB_PXA_STUART
+	bool "STUART"
 endchoice
 
 choice
@@ -179,7 +209,7 @@ config KGDB_BAUDRATE
 	int "Debug serial port baud rate"
 	depends on (KGDB_8250 && KGDB_SIMPLE_SERIAL) || \
 		KGDB_MPSC || KGDB_CPM_UART || \
-		KGDB_TXX9
+		KGDB_TXX9 || KGDB_PXA_SERIAL || KGDB_AMBA_PL011
 	default "115200"
 	help
 	  gdb and the kernel stub need to agree on the baud rate to be
@@ -195,6 +225,27 @@ config KGDB_PORT_NUM
 	help
 	  Pick the port number (0 based) for KGDB to use.
 
+config KGDB_AMBA_BASE
+	hex "AMBA PL011 Serial Port Base Address"
+	default 0x101f2000 if ARCH_VERSATILE
+	depends on KGDB_AMBA_PL011
+	help
+	  Base address of the AMBA port that KGDB will use.
+
+config KGDB_AMBA_UARTCLK
+	int "AMBAPL011 Serial UART Clock Frequency"
+	default 24000000 if ARCH_VERSATILE
+	depends on KGDB_AMBA_PL011
+	help
+	  Frequency (in HZ) of the ARM AMBA UART clock
+
+config KGDB_AMBA_IRQ
+	int "AMBA PL011 Serial Port IRQ"
+	default 13 if ARCH_VERSATILE
+	depends on KGDB_AMBA_PL011
+	help
+	  Pick the IRQ of the AMBA port that KGDB will use.
+
 config KGDB_8250_CONF_STRING
 	string "Configuration string for KGDB"
 	depends on KGDB_8250_NOMODULE && !KGDB_SIMPLE_SERIAL

             reply	other threads:[~2007-10-15 18:47 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-15 18:33 Jason Wessel [this message]
2008-01-17 13:12 ` [PATCH 14/21] KGDB: KGDB arch support for ARM Jan Kiszka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4713B281.8090702@windriver.com \
    --to=jason.wessel@windriver.com \
    --cc=linux-arm-kernel@lists.arm.linux.org.uk \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.