CC: Russell King <[EMAIL PROTECTED]>, Deepak Saxena <[EMAIL PROTECTED]>, George Davis <[EMAIL PROTECTED]>, Geoff Levand <[EMAIL PROTECTED]>, Nicolas Pitre <[EMAIL PROTECTED]> This adds a backend, written by Deepak Saxena <[EMAIL PROTECTED]> and George Davis <[EMAIL PROTECTED]> as well as support for the TI OMAP boards, ADI Coyote, PXA2xx, and ARM Versatile. Geoff Levand <[EMAIL PROTECTED]> 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.
--- linux-2.6.13-rc3-trini/arch/arm/kernel/Makefile | 1 linux-2.6.13-rc3-trini/arch/arm/kernel/kgdb-jmp.S | 30 + linux-2.6.13-rc3-trini/arch/arm/kernel/kgdb.c | 208 +++++++++++ linux-2.6.13-rc3-trini/arch/arm/kernel/setup.c | 5 linux-2.6.13-rc3-trini/arch/arm/kernel/traps.c | 11 linux-2.6.13-rc3-trini/arch/arm/mach-ixp2000/core.c | 5 linux-2.6.13-rc3-trini/arch/arm/mach-ixp2000/ixdp2x01.c | 6 linux-2.6.13-rc3-trini/arch/arm/mach-ixp4xx/coyote-setup.c | 5 linux-2.6.13-rc3-trini/arch/arm/mach-ixp4xx/ixdp425-setup.c | 10 linux-2.6.13-rc3-trini/arch/arm/mach-omap1/board-osk.c | 6 linux-2.6.13-rc3-trini/arch/arm/mach-omap1/serial.c | 4 linux-2.6.13-rc3-trini/arch/arm/mach-pxa/Makefile | 1 linux-2.6.13-rc3-trini/arch/arm/mach-pxa/kgdb-serial.c | 98 +++++ linux-2.6.13-rc3-trini/arch/arm/mach-versatile/kgdb_serial.c | 121 ++++++ linux-2.6.13-rc3-trini/arch/arm/mm/extable.c | 7 linux-2.6.13-rc3-trini/drivers/serial/amba-pl011.c | 2 linux-2.6.13-rc3-trini/drivers/serial/kgdb_8250.c | 16 linux-2.6.13-rc3-trini/include/asm-arm/kgdb.h | 90 ++++ linux-2.6.13-rc3-trini/include/asm-arm/system.h | 41 ++ linux-2.6.13-rc3-trini/lib/Kconfig.debug | 35 + 20 files changed, 695 insertions(+), 7 deletions(-) diff -puN /dev/null arch/arm/kernel/kgdb.c --- /dev/null 2005-07-25 10:57:32.312383000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/kernel/kgdb.c 2005-07-29 11:55:32.000000000 -0700 @@ -0,0 +1,208 @@ +/* + * arch/arm/kernel/kgdb.c + * + * ARM KGDB support + * + * Copyright (c) 2002-2004 MontaVista Software, Inc + * + * Authors: George Davis <[EMAIL PROTECTED]> + * Deepak Saxena <[EMAIL PROTECTED]> + */ +#include <linux/config.h> +#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 <asm/atomic.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/unistd.h> +#include <asm/ptrace.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[GDB_MAX_REGS - 1]; +} + +static inline struct pt_regs *kgdb_get_user_regs(struct task_struct *task) +{ + return (struct pt_regs *) + ((unsigned long)task->thread_info + THREAD_SIZE - + 8 - sizeof(struct pt_regs)); +} + +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 = kgdb_get_user_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 '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) +{ + kgdb_handle_exception(1, SIGTRAP, 0, regs); + + return 0; +} + +static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr) +{ + 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 + .gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe} +#endif +}; diff -puN /dev/null arch/arm/kernel/kgdb-jmp.S --- /dev/null 2005-07-25 10:57:32.312383000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/kernel/kgdb-jmp.S 2005-07-29 11:55:32.000000000 -0700 @@ -0,0 +1,30 @@ +/* + * 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. <[EMAIL PROTECTED]> + * [EMAIL PROTECTED] + * + * 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] + ldmia r0,{r0-pc}^ diff -puN arch/arm/kernel/Makefile~arm-lite arch/arm/kernel/Makefile --- linux-2.6.13-rc3/arch/arm/kernel/Makefile~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/kernel/Makefile 2005-07-29 11:55:32.000000000 -0700 @@ -19,6 +19,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_KGDB) += kgdb.o kgdb-jmp.o obj-$(CONFIG_IWMMXT) += iwmmxt.o AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt diff -puN arch/arm/kernel/setup.c~arm-lite arch/arm/kernel/setup.c --- linux-2.6.13-rc3/arch/arm/kernel/setup.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/kernel/setup.c 2005-07-29 11:55:32.000000000 -0700 @@ -785,6 +785,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 } diff -puN arch/arm/kernel/traps.c~arm-lite arch/arm/kernel/traps.c --- linux-2.6.13-rc3/arch/arm/kernel/traps.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/kernel/traps.c 2005-07-29 11:55:32.000000000 -0700 @@ -266,6 +266,7 @@ asmlinkage void do_undefinstr(struct pt_ unsigned int instr; struct undef_hook *hook; siginfo_t info; + mm_segment_t fs; void __user *pc; /* @@ -275,12 +276,15 @@ asmlinkage void do_undefinstr(struct pt_ */ regs->ARM_pc -= correction; + fs = get_fs(); + set_fs(KERNEL_DS); pc = (void __user *)instruction_pointer(regs); if (thumb_mode(regs)) { get_user(instr, (u16 __user *)pc); } else { get_user(instr, (u32 __user *)pc); } + set_fs(fs); spin_lock_irq(&undef_lock); list_for_each_entry(hook, &undef_hook, node) { @@ -663,6 +667,13 @@ EXPORT_SYMBOL(abort); void __init trap_init(void) { +#if defined(CONFIG_KGDB) + return; +} + +void __init early_trap_init(void) +{ +#endif extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; diff -puN arch/arm/mach-ixp2000/core.c~arm-lite arch/arm/mach-ixp2000/core.c --- linux-2.6.13-rc3/arch/arm/mach-ixp2000/core.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-ixp2000/core.c 2005-07-29 11:55:32.000000000 -0700 @@ -35,6 +35,7 @@ #include <asm/system.h> #include <asm/tlbflush.h> #include <asm/pgtable.h> +#include <asm/kgdb.h> #include <asm/mach/map.h> #include <asm/mach/time.h> @@ -145,6 +146,10 @@ void __init ixp2000_map_io(void) iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &ixp2000_serial_port); +#endif + /* Set slowport to 8-bit mode. */ ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1); } diff -puN arch/arm/mach-ixp2000/ixdp2x01.c~arm-lite arch/arm/mach-ixp2000/ixdp2x01.c --- linux-2.6.13-rc3/arch/arm/mach-ixp2000/ixdp2x01.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-ixp2000/ixdp2x01.c 2005-07-29 11:55:32.000000000 -0700 @@ -38,6 +38,7 @@ #include <asm/system.h> #include <asm/hardware.h> #include <asm/mach-types.h> +#include <asm/kgdb.h> #include <asm/mach/pci.h> #include <asm/mach/map.h> @@ -175,6 +176,11 @@ static void __init ixdp2x01_map_io(void) early_serial_setup(&ixdp2x01_serial_ports[0]); early_serial_setup(&ixdp2x01_serial_ports[1]); + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &ixdp2x01_serial_ports[0]); + kgdb8250_add_port(1, &ixdp2x01_serial_ports[1]); +#endif } diff -puN arch/arm/mach-ixp4xx/coyote-setup.c~arm-lite arch/arm/mach-ixp4xx/coyote-setup.c --- linux-2.6.13-rc3/arch/arm/mach-ixp4xx/coyote-setup.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-ixp4xx/coyote-setup.c 2005-07-29 11:55:32.000000000 -0700 @@ -96,9 +96,12 @@ static void __init coyote_init(void) coyote_uart_data[0].irq = IRQ_IXP4XX_UART1; } - ixp4xx_sys_init(); platform_add_devices(coyote_devices, ARRAY_SIZE(coyote_devices)); + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &coyote_serial_port); +#endif } #ifdef CONFIG_ARCH_ADI_COYOTE diff -puN arch/arm/mach-ixp4xx/ixdp425-setup.c~arm-lite arch/arm/mach-ixp4xx/ixdp425-setup.c --- linux-2.6.13-rc3/arch/arm/mach-ixp4xx/ixdp425-setup.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-ixp4xx/ixdp425-setup.c 2005-07-29 11:55:32.000000000 -0700 @@ -23,6 +23,7 @@ #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> +#include <asm/kgdb.h> void __init ixdp425_map_io(void) { @@ -82,7 +83,7 @@ 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, + .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, .iotype = UPIO_MEM, .regshift = 2, .uartclk = IXP4XX_UART_XTAL, @@ -91,7 +92,7 @@ static struct plat_serial8250_port ixdp4 .mapbase = IXP4XX_UART2_BASE_PHYS, .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, .irq = IRQ_IXP4XX_UART1, - .flags = UPF_BOOT_AUTOCONF, + .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ, .iotype = UPIO_MEM, .regshift = 2, .uartclk = IXP4XX_UART_XTAL, @@ -126,6 +127,11 @@ static void __init ixdp425_init(void) } platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices)); + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &ixdp425_serial_ports[0]); + kgdb8250_add_port(1, &ixdp425_serial_ports[1]); +#endif } MACHINE_START(IXDP425, "Intel IXDP425 Development Platform") diff -puN arch/arm/mach-omap1/board-osk.c~arm-lite arch/arm/mach-omap1/board-osk.c --- linux-2.6.13-rc3/arch/arm/mach-omap1/board-osk.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-omap1/board-osk.c 2005-07-29 11:55:32.000000000 -0700 @@ -41,12 +41,14 @@ #include <asm/arch/tc.h> #include <asm/arch/common.h> +#if 0 static struct map_desc osk5912_io_desc[] __initdata = { { OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE, MT_DEVICE }, }; +#endif -static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0}; +static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; static struct resource osk5912_smc91x_resources[] = { [0] = { @@ -153,7 +155,7 @@ static void __init osk_init(void) static void __init osk_map_io(void) { omap_map_common_io(); - iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc)); + //iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc)); omap_serial_init(osk_serial_ports); } diff -puN arch/arm/mach-omap1/serial.c~arm-lite arch/arm/mach-omap1/serial.c --- linux-2.6.13-rc3/arch/arm/mach-omap1/serial.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-omap1/serial.c 2005-07-29 11:55:32.000000000 -0700 @@ -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> @@ -190,6 +191,9 @@ void __init omap_serial_init(int ports[O break; } omap_serial_reset(&serial_platform_data[i]); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_platform_port(i, &serial_platform_data[i]); +#endif } } diff -puN /dev/null arch/arm/mach-pxa/kgdb-serial.c --- /dev/null 2005-07-25 10:57:32.312383000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-pxa/kgdb-serial.c 2005-07-29 11:55:32.000000000 -0700 @@ -0,0 +1,98 @@ +/* + * 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/config.h> +#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_PXA_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(int 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, +}; diff -puN arch/arm/mach-pxa/Makefile~arm-lite arch/arm/mach-pxa/Makefile --- linux-2.6.13-rc3/arch/arm/mach-pxa/Makefile~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-pxa/Makefile 2005-07-29 11:55:32.000000000 -0700 @@ -24,6 +24,7 @@ obj-$(CONFIG_LEDS) += $(led-y) # Misc features obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_KGDB_PXA_SERIAL) += kgdb-serial.o ifeq ($(CONFIG_PXA27x),y) obj-$(CONFIG_PM) += standby.o diff -puN /dev/null arch/arm/mach-versatile/kgdb_serial.c --- /dev/null 2005-07-25 10:57:32.312383000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mach-versatile/kgdb_serial.c 2005-07-29 11:55:32.000000000 -0700 @@ -0,0 +1,121 @@ +/* + * arch/arm/mach-versatile/kgdb_serial.c + * + * Author: Manish Lachwani, [EMAIL PROTECTED] + * + * 2005 (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. + * + * Support for KGDB on ARM Versatile. + */ +#include <linux/config.h> +#include <linux/serial_reg.h> +#include <linux/kgdb.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/hardware.h> +#include <asm/hardware/amba_serial.h> +#include <asm/arch-versatile/hardware.h> + +#define ARM_BAUD_38400 23 +/* + * Functions that will be used later + */ +#define UART_GET_INT_STATUS(p) readb((p) + UART010_IIR) +#define UART_GET_MIS(p) readw((p) + UART011_MIS) +#define UART_PUT_ICR(p, c) writel((c), (p) + UART010_ICR) +#define UART_GET_FR(p) readb((p) + UART01x_FR) +#define UART_GET_CHAR(p) readb((p) + UART01x_DR) +#define UART_PUT_CHAR(p, c) writel((c), (p) + UART01x_DR) +#define UART_GET_RSR(p) readb((p) + UART01x_RSR) +#define UART_GET_CR(p) readb((p) + UART010_CR) +#define UART_PUT_CR(p,c) writel((c), (p) + UART010_CR) +#define UART_GET_LCRL(p) readb((p) + UART010_LCRL) +#define UART_PUT_LCRL(p,c) writel((c), (p) + UART010_LCRL) +#define UART_GET_LCRM(p) readb((p) + UART010_LCRM) +#define UART_PUT_LCRM(p,c) writel((c), (p) + UART010_LCRM) +#define UART_GET_LCRH(p) readb((p) + UART010_LCRH) +#define UART_PUT_LCRH(p,c) writel((c), (p) + UART010_LCRH) +#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0) +#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0) +#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART01x_FR_TMSK) == 0) + +/* + * KGDB IRQ + */ +static int kgdb_irq = 12; +static volatile unsigned char *port = NULL; + +static int kgdb_serial_init(void) +{ + int rate = ARM_BAUD_38400; + + port = IO_ADDRESS(0x101F1000); + UART_PUT_CR(port, 0); + + /* Set baud rate */ + UART_PUT_LCRM(port, ((rate & 0xf00) >> 8)); + UART_PUT_LCRL(port, (rate & 0xff)); + UART_PUT_LCRH(port, UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN); + UART_PUT_CR(port, UART01x_CR_UARTEN); + + return 0; +} + +static void kgdb_serial_putchar(int ch) +{ + unsigned int status; + + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + + UART_PUT_CHAR(port, ch); +} + +static int kgdb_serial_getchar(void) +{ + unsigned int status; + int ch; + + do { + status = UART_GET_FR(port); + } while (!UART_RX_DATA(status)); + ch = UART_GET_CHAR(port); + return ch; +} + +static struct uart_port kgdb_amba_port = { + .irq = 12, + .iobase = 0, + .iotype = UPIO_MEM, + .membase = (unsigned char *)IO_ADDRESS(0x101F1000), +}; + +static irqreturn_t kgdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int status = UART_GET_MIS(port); + + if (irq != kgdb_irq) + return IRQ_NONE; + + if (status & 0x40) + breakpoint(); + + return IRQ_HANDLED; +} + +static void __init kgdb_hookup_irq(void) +{ + request_irq(kgdb_irq, kgdb_interrupt, SA_SHIRQ, "GDB-stub", + &kgdb_amba_port); +} + +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, +}; diff -puN arch/arm/mm/extable.c~arm-lite arch/arm/mm/extable.c --- linux-2.6.13-rc3/arch/arm/mm/extable.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/arch/arm/mm/extable.c 2005-07-29 11:55:32.000000000 -0700 @@ -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; } diff -puN drivers/serial/amba-pl011.c~arm-lite drivers/serial/amba-pl011.c --- linux-2.6.13-rc3/drivers/serial/amba-pl011.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/drivers/serial/amba-pl011.c 2005-07-29 11:55:32.000000000 -0700 @@ -350,7 +350,7 @@ 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, SA_SHIRQ, "uart-pl011", uap); if (retval) goto clk_dis; diff -puN drivers/serial/kgdb_8250.c~arm-lite drivers/serial/kgdb_8250.c --- linux-2.6.13-rc3/drivers/serial/kgdb_8250.c~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/drivers/serial/kgdb_8250.c 2005-07-29 11:55:32.000000000 -0700 @@ -319,6 +319,22 @@ static int kgdb8250_init(void) /* Disable UART interrupts, set DTR and RTS high and set speed. */ cval = 0x3; +#if defined(CONFIG_ARCH_OMAP1510) + /* Workaround to enable 115200 baud on OMAP1510 internal ports */ + if (cpu_is_omap1510() && is_omap_port((void *)kgdb8250_addr)) { + if (kgdb8250_baud == 115200) { + base_baud = 1; + kgdb8250_baud = 1; + serial_outb(1, kgdb8250_addr + + (UART_OMAP_OSC_12M_SEL << + KGDB8250_REG_SHIFT)); + } else { + serial_outb(0, kgdb8250_addr + + (UART_OMAP_OSC_12M_SEL << + KGDB8250_REG_SHIFT)); + } + } +#endif /* set DLAB */ serial_outb(cval | UART_LCR_DLAB, kgdb8250_addr + (UART_LCR << KGDB8250_REG_SHIFT)); diff -puN /dev/null include/asm-arm/kgdb.h --- /dev/null 2005-07-25 10:57:32.312383000 -0700 +++ linux-2.6.13-rc3-trini/include/asm-arm/kgdb.h 2005-07-29 12:48:10.000000000 -0700 @@ -0,0 +1,90 @@ +/* + * include/asm-arm/kgdb.h + * + * ARM KGDB support + * + * Author: Deepak Saxena <[EMAIL PROTECTED]> + * + * Copyright (C) 2002 MontaVista Software Inc. + * + */ + +#ifndef __ASM_KGDB_H__ +#define __ASM_KGDB_H__ + +#include <linux/config.h> +#include <asm/ptrace.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; + +/* + * From Amit S. Kale: + * + * In the register packet, words 0-15 are R0 to R10, FP, IP, SP, LR, PC. But + * Register 16 isn't cpsr. GDB passes CPSR in word 25. There are 9 words in + * between which are unused. Passing only 26 words to gdb is sufficient. + * GDB can figure out that floating point registers are not passed. + * GDB_MAX_REGS should be 26. + */ +#define GDB_MAX_REGS (26) + +#define KGDB_MAX_NO_CPUS 1 +#define BUFMAX 400 +#define NUMREGBYTES (GDB_MAX_REGS << 2) +#define NUMCRITREGBYTES (32 << 2) +#define CHECK_EXCEPTION_STACK() 1 + +#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) + +#define CHECK_EXCEPTION_STACK() 1 + +#endif // !__ASSEMBLY__ +#endif // __ASM_KGDB_H__ diff -puN include/asm-arm/system.h~arm-lite include/asm-arm/system.h --- linux-2.6.13-rc3/include/asm-arm/system.h~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/include/asm-arm/system.h 2005-07-29 11:55:32.000000000 -0700 @@ -371,6 +371,47 @@ static inline unsigned long __xchg(unsig return ret; } +#define __HAVE_ARCH_CMPXCHG 1 + +#include <asm/types.h> + +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); + +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))); \ + }) #endif /* __ASSEMBLY__ */ #define arch_align_stack(x) (x) diff -puN lib/Kconfig.debug~arm-lite lib/Kconfig.debug --- linux-2.6.13-rc3/lib/Kconfig.debug~arm-lite 2005-07-29 11:55:32.000000000 -0700 +++ linux-2.6.13-rc3-trini/lib/Kconfig.debug 2005-07-29 13:18:12.000000000 -0700 @@ -163,7 +163,7 @@ config FRAME_POINTER config KGDB bool "KGDB: kernel debugging with remote gdb" - depends on DEBUG_KERNEL && (X86 || MIPS32 || (SUPERH && !SUPERH64) || IA64 || X86_64 || ((!SMP || BROKEN) && PPC32)) + depends on DEBUG_KERNEL && (ARM || X86 || MIPS32 || (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 @@ -189,8 +189,10 @@ choice prompt "Method for KGDB communication" depends on KGDB default KGDB_ONLY_MODULES + default KGDB_ARM_VERSATILE if ARCH_VERSATILE default KGDB_SIBYTE if SIBYTE_SB1xxx_SOC default KGDB_MPSC if SERIAL_MPSC + default KGDB_PXA_SERIAL if ARCH_PXA help There are a number of different ways in which you can communicate with KGDB. The most common is via serial, with the 8250 driver @@ -227,6 +229,16 @@ config KGDB_SIBYTE bool "KGDB: On the Broadcom SWARM serial port" depends on MIPS && SIBYTE_SB1xxx_SOC +config KGDB_ARM_VERSATILE + bool "KGDB: On ARM Versatile" + depends on ARM && ARCH_VERSATILE + help + Enables the KGDB serial driver for the ARM Versatile + +config KGDB_PXA_SERIAL + bool "KGDB: On the PXA2xx serial port" + depends on ARCH_PXA + config KGDB_SH_SCI bool "KGDB: On SH SCI(F) serial port" depends on SUPERH && SERIAL_SH_SCI @@ -296,6 +308,27 @@ config KGDB_PORT_3 bool "Third serial port" endchoice +choice + prompt "PXA serial UART 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 + +config KGDB_PXA_BAUDRATE + int "UART baudrate for KGDB" + depends on KGDB_PXA_SERIAL + default "115200" + config KGDB_PORT hex "hex I/O port address of the debug serial port" depends on !KGDB_SIMPLE_SERIAL && KGDB_8250 && !IA64 _ - 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/