aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/kgdb.c201
-rw-r--r--arch/arm/kernel/setup.c2
-rw-r--r--arch/arm/kernel/traps.c5
-rw-r--r--include/asm-arm/kgdb.h104
-rw-r--r--include/asm-arm/traps.h2
7 files changed, 316 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c7ad324ddf2c..d048f6887d0b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -12,6 +12,7 @@ config ARM
12 select RTC_LIB 12 select RTC_LIB
13 select SYS_SUPPORTS_APM_EMULATION 13 select SYS_SUPPORTS_APM_EMULATION
14 select HAVE_OPROFILE 14 select HAVE_OPROFILE
15 select HAVE_ARCH_KGDB
15 select HAVE_KPROBES if (!XIP_KERNEL) 16 select HAVE_KPROBES if (!XIP_KERNEL)
16 select HAVE_KRETPROBES if (HAVE_KPROBES) 17 select HAVE_KRETPROBES if (HAVE_KPROBES)
17 select HAVE_FTRACE if (!XIP_KERNEL) 18 select HAVE_FTRACE if (!XIP_KERNEL)
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index eb9092ca8008..1d296fc8494e 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o
28obj-$(CONFIG_ATAGS_PROC) += atags.o 28obj-$(CONFIG_ATAGS_PROC) += atags.o
29obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o 29obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
30obj-$(CONFIG_ARM_THUMBEE) += thumbee.o 30obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
31obj-$(CONFIG_KGDB) += kgdb.o
31 32
32obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o 33obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
33AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 34AFLAGS_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 000000000000..aaffaecffcd1
--- /dev/null
+++ b/arch/arm/kernel/kgdb.c
@@ -0,0 +1,201 @@
1/*
2 * arch/arm/kernel/kgdb.c
3 *
4 * ARM KGDB support
5 *
6 * Copyright (c) 2002-2004 MontaVista Software, Inc
7 * Copyright (c) 2008 Wind River Systems, Inc.
8 *
9 * Authors: George Davis <davis_g@mvista.com>
10 * Deepak Saxena <dsaxena@plexity.net>
11 */
12#include <linux/kgdb.h>
13#include <asm/traps.h>
14
15/* Make a local copy of the registers passed into the handler (bletch) */
16void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
17{
18 int regno;
19
20 /* Initialize all to zero. */
21 for (regno = 0; regno < GDB_MAX_REGS; regno++)
22 gdb_regs[regno] = 0;
23
24 gdb_regs[_R0] = kernel_regs->ARM_r0;
25 gdb_regs[_R1] = kernel_regs->ARM_r1;
26 gdb_regs[_R2] = kernel_regs->ARM_r2;
27 gdb_regs[_R3] = kernel_regs->ARM_r3;
28 gdb_regs[_R4] = kernel_regs->ARM_r4;
29 gdb_regs[_R5] = kernel_regs->ARM_r5;
30 gdb_regs[_R6] = kernel_regs->ARM_r6;
31 gdb_regs[_R7] = kernel_regs->ARM_r7;
32 gdb_regs[_R8] = kernel_regs->ARM_r8;
33 gdb_regs[_R9] = kernel_regs->ARM_r9;
34 gdb_regs[_R10] = kernel_regs->ARM_r10;
35 gdb_regs[_FP] = kernel_regs->ARM_fp;
36 gdb_regs[_IP] = kernel_regs->ARM_ip;
37 gdb_regs[_SPT] = kernel_regs->ARM_sp;
38 gdb_regs[_LR] = kernel_regs->ARM_lr;
39 gdb_regs[_PC] = kernel_regs->ARM_pc;
40 gdb_regs[_CPSR] = kernel_regs->ARM_cpsr;
41}
42
43/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
44void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
45{
46 kernel_regs->ARM_r0 = gdb_regs[_R0];
47 kernel_regs->ARM_r1 = gdb_regs[_R1];
48 kernel_regs->ARM_r2 = gdb_regs[_R2];
49 kernel_regs->ARM_r3 = gdb_regs[_R3];
50 kernel_regs->ARM_r4 = gdb_regs[_R4];
51 kernel_regs->ARM_r5 = gdb_regs[_R5];
52 kernel_regs->ARM_r6 = gdb_regs[_R6];
53 kernel_regs->ARM_r7 = gdb_regs[_R7];
54 kernel_regs->ARM_r8 = gdb_regs[_R8];
55 kernel_regs->ARM_r9 = gdb_regs[_R9];
56 kernel_regs->ARM_r10 = gdb_regs[_R10];
57 kernel_regs->ARM_fp = gdb_regs[_FP];
58 kernel_regs->ARM_ip = gdb_regs[_IP];
59 kernel_regs->ARM_sp = gdb_regs[_SPT];
60 kernel_regs->ARM_lr = gdb_regs[_LR];
61 kernel_regs->ARM_pc = gdb_regs[_PC];
62 kernel_regs->ARM_cpsr = gdb_regs[_CPSR];
63}
64
65void
66sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
67{
68 struct pt_regs *thread_regs;
69 int regno;
70
71 /* Just making sure... */
72 if (task == NULL)
73 return;
74
75 /* Initialize to zero */
76 for (regno = 0; regno < GDB_MAX_REGS; regno++)
77 gdb_regs[regno] = 0;
78
79 /* Otherwise, we have only some registers from switch_to() */
80 thread_regs = task_pt_regs(task);
81 gdb_regs[_R0] = thread_regs->ARM_r0;
82 gdb_regs[_R1] = thread_regs->ARM_r1;
83 gdb_regs[_R2] = thread_regs->ARM_r2;
84 gdb_regs[_R3] = thread_regs->ARM_r3;
85 gdb_regs[_R4] = thread_regs->ARM_r4;
86 gdb_regs[_R5] = thread_regs->ARM_r5;
87 gdb_regs[_R6] = thread_regs->ARM_r6;
88 gdb_regs[_R7] = thread_regs->ARM_r7;
89 gdb_regs[_R8] = thread_regs->ARM_r8;
90 gdb_regs[_R9] = thread_regs->ARM_r9;
91 gdb_regs[_R10] = thread_regs->ARM_r10;
92 gdb_regs[_FP] = thread_regs->ARM_fp;
93 gdb_regs[_IP] = thread_regs->ARM_ip;
94 gdb_regs[_SPT] = thread_regs->ARM_sp;
95 gdb_regs[_LR] = thread_regs->ARM_lr;
96 gdb_regs[_PC] = thread_regs->ARM_pc;
97 gdb_regs[_CPSR] = thread_regs->ARM_cpsr;
98}
99
100static int compiled_break;
101
102int kgdb_arch_handle_exception(int exception_vector, int signo,
103 int err_code, char *remcom_in_buffer,
104 char *remcom_out_buffer,
105 struct pt_regs *linux_regs)
106{
107 unsigned long addr;
108 char *ptr;
109
110 switch (remcom_in_buffer[0]) {
111 case 'D':
112 case 'k':
113 case 'c':
114 kgdb_contthread = NULL;
115
116 /*
117 * Try to read optional parameter, pc unchanged if no parm.
118 * If this was a compiled breakpoint, we need to move
119 * to the next instruction or we will just breakpoint
120 * over and over again.
121 */
122 ptr = &remcom_in_buffer[1];
123 if (kgdb_hex2long(&ptr, &addr))
124 linux_regs->ARM_pc = addr;
125 else if (compiled_break == 1)
126 linux_regs->ARM_pc += 4;
127
128 compiled_break = 0;
129
130 return 0;
131 }
132
133 return -1;
134}
135
136static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
137{
138 kgdb_handle_exception(1, SIGTRAP, 0, regs);
139
140 return 0;
141}
142
143static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
144{
145 compiled_break = 1;
146 kgdb_handle_exception(1, SIGTRAP, 0, regs);
147
148 return 0;
149}
150
151static struct undef_hook kgdb_brkpt_hook = {
152 .instr_mask = 0xffffffff,
153 .instr_val = KGDB_BREAKINST,
154 .fn = kgdb_brk_fn
155};
156
157static struct undef_hook kgdb_compiled_brkpt_hook = {
158 .instr_mask = 0xffffffff,
159 .instr_val = KGDB_COMPILED_BREAK,
160 .fn = kgdb_compiled_brk_fn
161};
162
163/**
164 * kgdb_arch_init - Perform any architecture specific initalization.
165 *
166 * This function will handle the initalization of any architecture
167 * specific callbacks.
168 */
169int kgdb_arch_init(void)
170{
171 register_undef_hook(&kgdb_brkpt_hook);
172 register_undef_hook(&kgdb_compiled_brkpt_hook);
173
174 return 0;
175}
176
177/**
178 * kgdb_arch_exit - Perform any architecture specific uninitalization.
179 *
180 * This function will handle the uninitalization of any architecture
181 * specific callbacks, for dynamic registration and unregistration.
182 */
183void kgdb_arch_exit(void)
184{
185 unregister_undef_hook(&kgdb_brkpt_hook);
186 unregister_undef_hook(&kgdb_compiled_brkpt_hook);
187}
188
189/*
190 * Register our undef instruction hooks with ARM undef core.
191 * We regsiter a hook specifically looking for the KGB break inst
192 * and we handle the normal undef case within the do_undefinstr
193 * handler.
194 */
195struct kgdb_arch arch_kgdb_ops = {
196#ifndef __ARMEB__
197 .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}
198#else /* ! __ARMEB__ */
199 .gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe}
200#endif
201};
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index b7b0720bc1bb..38f0e7940a13 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -36,6 +36,7 @@
36#include <asm/mach/arch.h> 36#include <asm/mach/arch.h>
37#include <asm/mach/irq.h> 37#include <asm/mach/irq.h>
38#include <asm/mach/time.h> 38#include <asm/mach/time.h>
39#include <asm/traps.h>
39 40
40#include "compat.h" 41#include "compat.h"
41#include "atags.h" 42#include "atags.h"
@@ -853,6 +854,7 @@ void __init setup_arch(char **cmdline_p)
853 conswitchp = &dummy_con; 854 conswitchp = &dummy_con;
854#endif 855#endif
855#endif 856#endif
857 early_trap_init();
856} 858}
857 859
858 860
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 5595fdd75e82..7277aef83098 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -708,6 +708,11 @@ EXPORT_SYMBOL(abort);
708 708
709void __init trap_init(void) 709void __init trap_init(void)
710{ 710{
711 return;
712}
713
714void __init early_trap_init(void)
715{
711 unsigned long vectors = CONFIG_VECTORS_BASE; 716 unsigned long vectors = CONFIG_VECTORS_BASE;
712 extern char __stubs_start[], __stubs_end[]; 717 extern char __stubs_start[], __stubs_end[];
713 extern char __vectors_start[], __vectors_end[]; 718 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 000000000000..67af4b841984
--- /dev/null
+++ b/include/asm-arm/kgdb.h
@@ -0,0 +1,104 @@
1/*
2 * ARM KGDB support
3 *
4 * Author: Deepak Saxena <dsaxena@mvista.com>
5 *
6 * Copyright (C) 2002 MontaVista Software Inc.
7 *
8 */
9
10#ifndef __ARM_KGDB_H__
11#define __ARM_KGDB_H__
12
13#include <linux/ptrace.h>
14
15/*
16 * GDB assumes that we're a user process being debugged, so
17 * it will send us an SWI command to write into memory as the
18 * debug trap. When an SWI occurs, the next instruction addr is
19 * placed into R14_svc before jumping to the vector trap.
20 * This doesn't work for kernel debugging as we are already in SVC
21 * we would loose the kernel's LR, which is a bad thing. This
22 * is bad thing.
23 *
24 * By doing this as an undefined instruction trap, we force a mode
25 * switch from SVC to UND mode, allowing us to save full kernel state.
26 *
27 * We also define a KGDB_COMPILED_BREAK which can be used to compile
28 * in breakpoints. This is important for things like sysrq-G and for
29 * the initial breakpoint from trap_init().
30 *
31 * Note to ARM HW designers: Add real trap support like SH && PPC to
32 * make our lives much much simpler. :)
33 */
34#define BREAK_INSTR_SIZE 4
35#define GDB_BREAKINST 0xef9f0001
36#define KGDB_BREAKINST 0xe7ffdefe
37#define KGDB_COMPILED_BREAK 0xe7ffdeff
38#define CACHE_FLUSH_IS_SAFE 1
39
40#ifndef __ASSEMBLY__
41
42static inline void arch_kgdb_breakpoint(void)
43{
44 asm(".word 0xe7ffdeff");
45}
46
47extern void kgdb_handle_bus_error(void);
48extern int kgdb_fault_expected;
49
50#endif /* !__ASSEMBLY__ */
51
52/*
53 * From Kevin Hilman:
54 *
55 * gdb is expecting the following registers layout.
56 *
57 * r0-r15: 1 long word each
58 * f0-f7: unused, 3 long words each !!
59 * fps: unused, 1 long word
60 * cpsr: 1 long word
61 *
62 * Even though f0-f7 and fps are not used, they need to be
63 * present in the registers sent for correct processing in
64 * the host-side gdb.
65 *
66 * In particular, it is crucial that CPSR is in the right place,
67 * otherwise gdb will not be able to correctly interpret stepping over
68 * conditional branches.
69 */
70#define _GP_REGS 16
71#define _FP_REGS 8
72#define _EXTRA_REGS 2
73#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
74
75#define KGDB_MAX_NO_CPUS 1
76#define BUFMAX 400
77#define NUMREGBYTES (GDB_MAX_REGS << 2)
78#define NUMCRITREGBYTES (32 << 2)
79
80#define _R0 0
81#define _R1 1
82#define _R2 2
83#define _R3 3
84#define _R4 4
85#define _R5 5
86#define _R6 6
87#define _R7 7
88#define _R8 8
89#define _R9 9
90#define _R10 10
91#define _FP 11
92#define _IP 12
93#define _SPT 13
94#define _LR 14
95#define _PC 15
96#define _CPSR (GDB_MAX_REGS - 1)
97
98/*
99 * So that we can denote the end of a frame for tracing,
100 * in the simple case:
101 */
102#define CFI_END_FRAME(func) __CFI_END_FRAME(_PC, _SPT, func)
103
104#endif /* __ASM_KGDB_H__ */
diff --git a/include/asm-arm/traps.h b/include/asm-arm/traps.h
index f1541afcf85c..aa399aec568e 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)
24 ptr < (unsigned long)&__exception_text_end; 24 ptr < (unsigned long)&__exception_text_end;
25} 25}
26 26
27extern void __init early_trap_init(void);
28
27#endif 29#endif