Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758683AbYGRTyR (ORCPT ); Fri, 18 Jul 2008 15:54:17 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755025AbYGRTyG (ORCPT ); Fri, 18 Jul 2008 15:54:06 -0400 Received: from plexity.net ([206.123.115.38]:43123 "EHLO plexity.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754269AbYGRTyF (ORCPT ); Fri, 18 Jul 2008 15:54:05 -0400 X-Greylist: delayed 562 seconds by postgrey-1.27 at vger.kernel.org; Fri, 18 Jul 2008 15:54:04 EDT Date: Fri, 18 Jul 2008 11:44:29 -0700 From: Deepak Saxena To: Jason Wessel Cc: linux-kernel@vger.kernel.org, rmk@arm.linux.org.uk, linux-arm-kernel@lists.arm.linux.org.uk Subject: Re: [PATCH 1/4] kgdb: support for ARCH=arm Message-ID: <20080718184429.GA10770@plexity.net> Reply-To: dsaxena@plexity.net References: <1216124876-19108-1-git-send-email-jason.wessel@windriver.com> <1216124876-19108-2-git-send-email-jason.wessel@windriver.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1216124876-19108-2-git-send-email-jason.wessel@windriver.com> Organization: Plexity Networks User-Agent: Mutt/1.5.11 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 13621 Lines: 437 On Jul 15 2008, at 07:27, Jason Wessel was caught saying: > This patch adds the ARCH=arm specific a kgdb backend, originally > written by Deepak Saxena and George Davis > . Geoff Levand , > Nicolas Pitre, Manish Lachwani, and Jason Wessel have contributed > various fixups here as well. Acked-By: Deepak Saxena > The KGDB patch makes one change to the core ARM architecture such that > the traps are initialized early for use with the debugger or other > subsystems. > > [ mingo@elte.hu: small cleanups. ] > [ ben-linux@fluff.org: fixed early_trap_init ] > > Signed-off-by: Jason Wessel > --- > arch/arm/Kconfig | 1 + > arch/arm/kernel/Makefile | 1 + > arch/arm/kernel/kgdb.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++ > arch/arm/kernel/setup.c | 2 + > arch/arm/kernel/traps.c | 5 + > include/asm-arm/kgdb.h | 104 ++++++++++++++++++++++++ > include/asm-arm/traps.h | 2 + > 7 files changed, 316 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/kernel/kgdb.c > create mode 100644 include/asm-arm/kgdb.h > > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig > index 258f136..fd4d803 100644 > --- a/arch/arm/Kconfig > +++ b/arch/arm/Kconfig > @@ -12,6 +12,7 @@ config ARM > select RTC_LIB > select SYS_SUPPORTS_APM_EMULATION > select HAVE_OPROFILE > + select HAVE_ARCH_KGDB > select HAVE_KPROBES if (!XIP_KERNEL) > select HAVE_KRETPROBES if (HAVE_KPROBES) > select HAVE_FTRACE if (!XIP_KERNEL) > diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile > index eb9092c..1d296fc 100644 > --- a/arch/arm/kernel/Makefile > +++ b/arch/arm/kernel/Makefile > @@ -28,6 +28,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o > obj-$(CONFIG_ATAGS_PROC) += atags.o > obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o > obj-$(CONFIG_ARM_THUMBEE) += thumbee.o > +obj-$(CONFIG_KGDB) += kgdb.o > > obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o > AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 > diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c > new file mode 100644 > index 0000000..aaffaec > --- /dev/null > +++ b/arch/arm/kernel/kgdb.c > @@ -0,0 +1,201 @@ > +/* > + * arch/arm/kernel/kgdb.c > + * > + * ARM KGDB support > + * > + * Copyright (c) 2002-2004 MontaVista Software, Inc > + * Copyright (c) 2008 Wind River Systems, Inc. > + * > + * Authors: George Davis > + * Deepak Saxena > + */ > +#include > +#include > + > +/* Make a local copy of the registers passed into the handler (bletch) */ > +void pt_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[_SPT] = 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_pt_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[_SPT]; > + 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) > +{ > + struct pt_regs *thread_regs; > + int regno; > + > + /* 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; > + 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[_SPT] = 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) > +{ > + unsigned 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) > +{ > + 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 > +}; > + > +/** > + * kgdb_arch_init - Perform any architecture specific initalization. > + * > + * This function will handle the initalization of any architecture > + * specific callbacks. > + */ > +int kgdb_arch_init(void) > +{ > + register_undef_hook(&kgdb_brkpt_hook); > + register_undef_hook(&kgdb_compiled_brkpt_hook); > + > + return 0; > +} > + > +/** > + * kgdb_arch_exit - Perform any architecture specific uninitalization. > + * > + * This function will handle the uninitalization of any architecture > + * specific callbacks, for dynamic registration and unregistration. > + */ > +void kgdb_arch_exit(void) > +{ > + unregister_undef_hook(&kgdb_brkpt_hook); > + unregister_undef_hook(&kgdb_compiled_brkpt_hook); > +} > + > +/* > + * 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. > + */ > +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 > +}; > diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c > index b7b0720..38f0e79 100644 > --- a/arch/arm/kernel/setup.c > +++ b/arch/arm/kernel/setup.c > @@ -36,6 +36,7 @@ > #include > #include > #include > +#include > > #include "compat.h" > #include "atags.h" > @@ -853,6 +854,7 @@ void __init setup_arch(char **cmdline_p) > conswitchp = &dummy_con; > #endif > #endif > + early_trap_init(); > } > > > diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c > index 5595fdd..7277aef 100644 > --- a/arch/arm/kernel/traps.c > +++ b/arch/arm/kernel/traps.c > @@ -708,6 +708,11 @@ EXPORT_SYMBOL(abort); > > void __init trap_init(void) > { > + return; > +} > + > +void __init early_trap_init(void) > +{ > unsigned long vectors = CONFIG_VECTORS_BASE; > extern char __stubs_start[], __stubs_end[]; > extern char __vectors_start[], __vectors_end[]; > diff --git a/include/asm-arm/kgdb.h b/include/asm-arm/kgdb.h > new file mode 100644 > index 0000000..67af4b8 > --- /dev/null > +++ b/include/asm-arm/kgdb.h > @@ -0,0 +1,104 @@ > +/* > + * ARM KGDB support > + * > + * Author: Deepak Saxena > + * > + * Copyright (C) 2002 MontaVista Software Inc. > + * > + */ > + > +#ifndef __ARM_KGDB_H__ > +#define __ARM_KGDB_H__ > + > +#include > + > +/* > + * 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__ > + > +static inline void arch_kgdb_breakpoint(void) > +{ > + 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 _SPT 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, _SPT, func) > + > +#endif /* __ASM_KGDB_H__ */ > diff --git a/include/asm-arm/traps.h b/include/asm-arm/traps.h > index f1541af..aa399ae 100644 > --- a/include/asm-arm/traps.h > +++ b/include/asm-arm/traps.h > @@ -24,4 +24,6 @@ static inline int in_exception_text(unsigned long ptr) > ptr < (unsigned long)&__exception_text_end; > } > > +extern void __init early_trap_init(void); > + > #endif > -- > 1.5.5.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ -- _____ __o Deepak Saxena - Living CarFree and CareFree (o> ------ -\<, "When I see an adult on a bicycle, I do not despair //\ ----- ( )/ ( ) for the future of the human race." -H.G Wells V_/_ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/