aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2008-07-23 12:30:15 -0400
committerJason Wessel <jason.wessel@windriver.com>2008-07-23 12:30:15 -0400
commit17ce452f7ea3df760b7f9f42453b6f6acd765217 (patch)
treea53c70b553363ce404ff49cb49ccc532cf4c7e78 /arch/powerpc/kernel
parent5cbad0ebf45c5417104b383dc0e34f64fa7f2473 (diff)
kgdb, powerpc: arch specific powerpc kgdb support
This patch removes the old kgdb reminants from ARCH=powerpc and implements the new style arch specific stub for the common kgdb core interface. It is possible to have xmon and kgdb in the same kernel, but you cannot use both at the same time because there is only one set of debug hooks. The arch specific kgdb implementation saves the previous state of the debug hooks and restores them if you unconfigure the kgdb I/O driver. Kgdb should have no impact on a kernel that has no kgdb I/O driver configured. Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/Makefile1
-rw-r--r--arch/powerpc/kernel/kgdb.c410
-rw-r--r--arch/powerpc/kernel/setup_32.c16
3 files changed, 411 insertions, 16 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index bf0b1fd0ec34..1a4094704b1f 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -74,6 +74,7 @@ obj-y += time.o prom.o traps.o setup-common.o \
74 misc_$(CONFIG_WORD_SIZE).o 74 misc_$(CONFIG_WORD_SIZE).o
75obj-$(CONFIG_PPC32) += entry_32.o setup_32.o 75obj-$(CONFIG_PPC32) += entry_32.o setup_32.o
76obj-$(CONFIG_PPC64) += dma_64.o iommu.o 76obj-$(CONFIG_PPC64) += dma_64.o iommu.o
77obj-$(CONFIG_KGDB) += kgdb.o
77obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o 78obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
78obj-$(CONFIG_MODULES) += ppc_ksyms.o 79obj-$(CONFIG_MODULES) += ppc_ksyms.o
79obj-$(CONFIG_BOOTX_TEXT) += btext.o 80obj-$(CONFIG_BOOTX_TEXT) += btext.o
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
new file mode 100644
index 000000000000..b4fdf2f2743c
--- /dev/null
+++ b/arch/powerpc/kernel/kgdb.c
@@ -0,0 +1,410 @@
1/*
2 * PowerPC backend to the KGDB stub.
3 *
4 * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu)
5 * Copyright (C) 2003 Timesys Corporation.
6 * Copyright (C) 2004-2006 MontaVista Software, Inc.
7 * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
8 * PPC32 support restored by Vitaly Wool <vwool@ru.mvista.com> and
9 * Sergei Shtylyov <sshtylyov@ru.mvista.com>
10 * Copyright (C) 2007-2008 Wind River Systems, Inc.
11 *
12 * This file is licensed under the terms of the GNU General Public License
13 * version 2. This program as licensed "as is" without any warranty of any
14 * kind, whether express or implied.
15 */
16
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/kgdb.h>
20#include <linux/smp.h>
21#include <linux/signal.h>
22#include <linux/ptrace.h>
23#include <asm/current.h>
24#include <asm/processor.h>
25#include <asm/machdep.h>
26
27/*
28 * This table contains the mapping between PowerPC hardware trap types, and
29 * signals, which are primarily what GDB understands. GDB and the kernel
30 * don't always agree on values, so we use constants taken from gdb-6.2.
31 */
32static struct hard_trap_info
33{
34 unsigned int tt; /* Trap type code for powerpc */
35 unsigned char signo; /* Signal that we map this trap into */
36} hard_trap_info[] = {
37 { 0x0100, 0x02 /* SIGINT */ }, /* system reset */
38 { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */
39 { 0x0300, 0x0b /* SIGSEGV */ }, /* data access */
40 { 0x0400, 0x0b /* SIGSEGV */ }, /* instruction access */
41 { 0x0500, 0x02 /* SIGINT */ }, /* external interrupt */
42 { 0x0600, 0x0a /* SIGBUS */ }, /* alignment */
43 { 0x0700, 0x05 /* SIGTRAP */ }, /* program check */
44 { 0x0800, 0x08 /* SIGFPE */ }, /* fp unavailable */
45 { 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */
46 { 0x0c00, 0x14 /* SIGCHLD */ }, /* system call */
47#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
48 { 0x2002, 0x05 /* SIGTRAP */ }, /* debug */
49#if defined(CONFIG_FSL_BOOKE)
50 { 0x2010, 0x08 /* SIGFPE */ }, /* spe unavailable */
51 { 0x2020, 0x08 /* SIGFPE */ }, /* spe unavailable */
52 { 0x2030, 0x08 /* SIGFPE */ }, /* spe fp data */
53 { 0x2040, 0x08 /* SIGFPE */ }, /* spe fp data */
54 { 0x2050, 0x08 /* SIGFPE */ }, /* spe fp round */
55 { 0x2060, 0x0e /* SIGILL */ }, /* performace monitor */
56 { 0x2900, 0x08 /* SIGFPE */ }, /* apu unavailable */
57 { 0x3100, 0x0e /* SIGALRM */ }, /* fixed interval timer */
58 { 0x3200, 0x02 /* SIGINT */ }, /* watchdog */
59#else /* ! CONFIG_FSL_BOOKE */
60 { 0x1000, 0x0e /* SIGALRM */ }, /* prog interval timer */
61 { 0x1010, 0x0e /* SIGALRM */ }, /* fixed interval timer */
62 { 0x1020, 0x02 /* SIGINT */ }, /* watchdog */
63 { 0x2010, 0x08 /* SIGFPE */ }, /* fp unavailable */
64 { 0x2020, 0x08 /* SIGFPE */ }, /* ap unavailable */
65#endif
66#else /* ! (defined(CONFIG_40x) || defined(CONFIG_BOOKE)) */
67 { 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step */
68#if defined(CONFIG_8xx)
69 { 0x1000, 0x04 /* SIGILL */ }, /* software emulation */
70#else /* ! CONFIG_8xx */
71 { 0x0f00, 0x04 /* SIGILL */ }, /* performance monitor */
72 { 0x0f20, 0x08 /* SIGFPE */ }, /* altivec unavailable */
73 { 0x1300, 0x05 /* SIGTRAP */ }, /* instruction address break */
74#if defined(CONFIG_PPC64)
75 { 0x1200, 0x05 /* SIGILL */ }, /* system error */
76 { 0x1500, 0x04 /* SIGILL */ }, /* soft patch */
77 { 0x1600, 0x04 /* SIGILL */ }, /* maintenance */
78 { 0x1700, 0x08 /* SIGFPE */ }, /* altivec assist */
79 { 0x1800, 0x04 /* SIGILL */ }, /* thermal */
80#else /* ! CONFIG_PPC64 */
81 { 0x1400, 0x02 /* SIGINT */ }, /* SMI */
82 { 0x1600, 0x08 /* SIGFPE */ }, /* altivec assist */
83 { 0x1700, 0x04 /* SIGILL */ }, /* TAU */
84 { 0x2000, 0x05 /* SIGTRAP */ }, /* run mode */
85#endif
86#endif
87#endif
88 { 0x0000, 0x00 } /* Must be last */
89};
90
91static int computeSignal(unsigned int tt)
92{
93 struct hard_trap_info *ht;
94
95 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
96 if (ht->tt == tt)
97 return ht->signo;
98
99 return SIGHUP; /* default for things we don't know about */
100}
101
102static int kgdb_call_nmi_hook(struct pt_regs *regs)
103{
104 kgdb_nmicallback(raw_smp_processor_id(), regs);
105 return 0;
106}
107
108#ifdef CONFIG_SMP
109void kgdb_roundup_cpus(unsigned long flags)
110{
111 smp_send_debugger_break(MSG_ALL_BUT_SELF);
112}
113#endif
114
115/* KGDB functions to use existing PowerPC64 hooks. */
116static int kgdb_debugger(struct pt_regs *regs)
117{
118 return kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs);
119}
120
121static int kgdb_handle_breakpoint(struct pt_regs *regs)
122{
123 if (user_mode(regs))
124 return 0;
125
126 if (kgdb_handle_exception(0, SIGTRAP, 0, regs) != 0)
127 return 0;
128
129 if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
130 regs->nip += 4;
131
132 return 1;
133}
134
135static int kgdb_singlestep(struct pt_regs *regs)
136{
137 struct thread_info *thread_info, *exception_thread_info;
138
139 if (user_mode(regs))
140 return 0;
141
142 /*
143 * On Book E and perhaps other processsors, singlestep is handled on
144 * the critical exception stack. This causes current_thread_info()
145 * to fail, since it it locates the thread_info by masking off
146 * the low bits of the current stack pointer. We work around
147 * this issue by copying the thread_info from the kernel stack
148 * before calling kgdb_handle_exception, and copying it back
149 * afterwards. On most processors the copy is avoided since
150 * exception_thread_info == thread_info.
151 */
152 thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1));
153 exception_thread_info = current_thread_info();
154
155 if (thread_info != exception_thread_info)
156 memcpy(exception_thread_info, thread_info, sizeof *thread_info);
157
158 kgdb_handle_exception(0, SIGTRAP, 0, regs);
159
160 if (thread_info != exception_thread_info)
161 memcpy(thread_info, exception_thread_info, sizeof *thread_info);
162
163 return 1;
164}
165
166static int kgdb_iabr_match(struct pt_regs *regs)
167{
168 if (user_mode(regs))
169 return 0;
170
171 if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
172 return 0;
173 return 1;
174}
175
176static int kgdb_dabr_match(struct pt_regs *regs)
177{
178 if (user_mode(regs))
179 return 0;
180
181 if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
182 return 0;
183 return 1;
184}
185
186#define PACK64(ptr, src) do { *(ptr++) = (src); } while (0)
187
188#define PACK32(ptr, src) do { \
189 u32 *ptr32; \
190 ptr32 = (u32 *)ptr; \
191 *(ptr32++) = (src); \
192 ptr = (unsigned long *)ptr32; \
193 } while (0)
194
195
196void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
197{
198 unsigned long *ptr = gdb_regs;
199 int reg;
200
201 memset(gdb_regs, 0, NUMREGBYTES);
202
203 for (reg = 0; reg < 32; reg++)
204 PACK64(ptr, regs->gpr[reg]);
205
206#ifdef CONFIG_FSL_BOOKE
207#ifdef CONFIG_SPE
208 for (reg = 0; reg < 32; reg++)
209 PACK64(ptr, current->thread.evr[reg]);
210#else
211 ptr += 32;
212#endif
213#else
214 /* fp registers not used by kernel, leave zero */
215 ptr += 32 * 8 / sizeof(long);
216#endif
217
218 PACK64(ptr, regs->nip);
219 PACK64(ptr, regs->msr);
220 PACK32(ptr, regs->ccr);
221 PACK64(ptr, regs->link);
222 PACK64(ptr, regs->ctr);
223 PACK32(ptr, regs->xer);
224
225 BUG_ON((unsigned long)ptr >
226 (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
227}
228
229void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
230{
231 struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
232 STACK_FRAME_OVERHEAD);
233 unsigned long *ptr = gdb_regs;
234 int reg;
235
236 memset(gdb_regs, 0, NUMREGBYTES);
237
238 /* Regs GPR0-2 */
239 for (reg = 0; reg < 3; reg++)
240 PACK64(ptr, regs->gpr[reg]);
241
242 /* Regs GPR3-13 are caller saved, not in regs->gpr[] */
243 ptr += 11;
244
245 /* Regs GPR14-31 */
246 for (reg = 14; reg < 32; reg++)
247 PACK64(ptr, regs->gpr[reg]);
248
249#ifdef CONFIG_FSL_BOOKE
250#ifdef CONFIG_SPE
251 for (reg = 0; reg < 32; reg++)
252 PACK64(ptr, p->thread.evr[reg]);
253#else
254 ptr += 32;
255#endif
256#else
257 /* fp registers not used by kernel, leave zero */
258 ptr += 32 * 8 / sizeof(long);
259#endif
260
261 PACK64(ptr, regs->nip);
262 PACK64(ptr, regs->msr);
263 PACK32(ptr, regs->ccr);
264 PACK64(ptr, regs->link);
265 PACK64(ptr, regs->ctr);
266 PACK32(ptr, regs->xer);
267
268 BUG_ON((unsigned long)ptr >
269 (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
270}
271
272#define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0)
273
274#define UNPACK32(dest, ptr) do { \
275 u32 *ptr32; \
276 ptr32 = (u32 *)ptr; \
277 dest = *(ptr32++); \
278 ptr = (unsigned long *)ptr32; \
279 } while (0)
280
281void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
282{
283 unsigned long *ptr = gdb_regs;
284 int reg;
285#ifdef CONFIG_SPE
286 union {
287 u32 v32[2];
288 u64 v64;
289 } acc;
290#endif
291
292 for (reg = 0; reg < 32; reg++)
293 UNPACK64(regs->gpr[reg], ptr);
294
295#ifdef CONFIG_FSL_BOOKE
296#ifdef CONFIG_SPE
297 for (reg = 0; reg < 32; reg++)
298 UNPACK64(current->thread.evr[reg], ptr);
299#else
300 ptr += 32;
301#endif
302#else
303 /* fp registers not used by kernel, leave zero */
304 ptr += 32 * 8 / sizeof(int);
305#endif
306
307 UNPACK64(regs->nip, ptr);
308 UNPACK64(regs->msr, ptr);
309 UNPACK32(regs->ccr, ptr);
310 UNPACK64(regs->link, ptr);
311 UNPACK64(regs->ctr, ptr);
312 UNPACK32(regs->xer, ptr);
313
314 BUG_ON((unsigned long)ptr >
315 (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
316}
317
318/*
319 * This function does PowerPC specific procesing for interfacing to gdb.
320 */
321int kgdb_arch_handle_exception(int vector, int signo, int err_code,
322 char *remcom_in_buffer, char *remcom_out_buffer,
323 struct pt_regs *linux_regs)
324{
325 char *ptr = &remcom_in_buffer[1];
326 unsigned long addr;
327
328 switch (remcom_in_buffer[0]) {
329 /*
330 * sAA..AA Step one instruction from AA..AA
331 * This will return an error to gdb ..
332 */
333 case 's':
334 case 'c':
335 /* handle the optional parameter */
336 if (kgdb_hex2long(&ptr, &addr))
337 linux_regs->nip = addr;
338
339 atomic_set(&kgdb_cpu_doing_single_step, -1);
340 /* set the trace bit if we're stepping */
341 if (remcom_in_buffer[0] == 's') {
342#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
343 mtspr(SPRN_DBCR0,
344 mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
345 linux_regs->msr |= MSR_DE;
346#else
347 linux_regs->msr |= MSR_SE;
348#endif
349 kgdb_single_step = 1;
350 if (kgdb_contthread)
351 atomic_set(&kgdb_cpu_doing_single_step,
352 raw_smp_processor_id());
353 }
354 return 0;
355 }
356
357 return -1;
358}
359
360/*
361 * Global data
362 */
363struct kgdb_arch arch_kgdb_ops = {
364 .gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08},
365};
366
367static int kgdb_not_implemented(struct pt_regs *regs)
368{
369 return 0;
370}
371
372static void *old__debugger_ipi;
373static void *old__debugger;
374static void *old__debugger_bpt;
375static void *old__debugger_sstep;
376static void *old__debugger_iabr_match;
377static void *old__debugger_dabr_match;
378static void *old__debugger_fault_handler;
379
380int kgdb_arch_init(void)
381{
382 old__debugger_ipi = __debugger_ipi;
383 old__debugger = __debugger;
384 old__debugger_bpt = __debugger_bpt;
385 old__debugger_sstep = __debugger_sstep;
386 old__debugger_iabr_match = __debugger_iabr_match;
387 old__debugger_dabr_match = __debugger_dabr_match;
388 old__debugger_fault_handler = __debugger_fault_handler;
389
390 __debugger_ipi = kgdb_call_nmi_hook;
391 __debugger = kgdb_debugger;
392 __debugger_bpt = kgdb_handle_breakpoint;
393 __debugger_sstep = kgdb_singlestep;
394 __debugger_iabr_match = kgdb_iabr_match;
395 __debugger_dabr_match = kgdb_dabr_match;
396 __debugger_fault_handler = kgdb_not_implemented;
397
398 return 0;
399}
400
401void kgdb_arch_exit(void)
402{
403 __debugger_ipi = old__debugger_ipi;
404 __debugger = old__debugger;
405 __debugger_bpt = old__debugger_bpt;
406 __debugger_sstep = old__debugger_sstep;
407 __debugger_iabr_match = old__debugger_iabr_match;
408 __debugger_dabr_match = old__debugger_dabr_match;
409 __debugger_fault_handler = old__debugger_fault_handler;
410}
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 4efebe88e64a..066e65c59b58 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -43,10 +43,6 @@
43 43
44#define DBG(fmt...) 44#define DBG(fmt...)
45 45
46#if defined CONFIG_KGDB
47#include <asm/kgdb.h>
48#endif
49
50extern void bootx_init(unsigned long r4, unsigned long phys); 46extern void bootx_init(unsigned long r4, unsigned long phys);
51 47
52int boot_cpuid; 48int boot_cpuid;
@@ -302,18 +298,6 @@ void __init setup_arch(char **cmdline_p)
302 298
303 xmon_setup(); 299 xmon_setup();
304 300
305#if defined(CONFIG_KGDB)
306 if (ppc_md.kgdb_map_scc)
307 ppc_md.kgdb_map_scc();
308 set_debug_traps();
309 if (strstr(cmd_line, "gdb")) {
310 if (ppc_md.progress)
311 ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
312 printk("kgdb breakpoint activated\n");
313 breakpoint();
314 }
315#endif
316
317 /* 301 /*
318 * Set cache line size based on type of cpu as a default. 302 * Set cache line size based on type of cpu as a default.
319 * Systems with OF can look in the properties on the cpu node(s) 303 * Systems with OF can look in the properties on the cpu node(s)