aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2006-12-13 03:40:05 -0500
committerPaul Mundt <lethal@linux-sh.org>2007-02-12 20:54:43 -0500
commitf413d0d9fa7abcecc40e115cf4aead372d164a75 (patch)
tree72146d33f19d338076c55b7597dc15ce3f357f2c
parentec2f9d1331f658433411c58077871e1eef4ee1b4 (diff)
sh: Use a jump call table for debug trap handlers.
This rips out most of the needlessly complicated sh_bios and kgdb trap handling, and forces it all through a common fast dispatch path. As more debug traps are inserted, it's important to keep them in sync for all of the parts, not just SH-3/4. As the SH-2 parts are unable to do traps in the >= 0x40 range, we restrict the debug traps to the 0x30-0x3f range on all parts, and also bump the kgdb breakpoint trap down in to this range (from 0xff to 0x3c) so it's possible to use for nommu. Optionally, this table can be padded out to catch spurious traps for SH-3/4, but we don't do that yet.. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/kernel/Makefile3
-rw-r--r--arch/sh/kernel/cpu/sh2/entry.S2
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S2
-rw-r--r--arch/sh/kernel/debugtraps.S41
-rw-r--r--arch/sh/kernel/entry-common.S119
-rw-r--r--arch/sh/kernel/kgdb_stub.c7
-rw-r--r--arch/sh/kernel/process.c24
-rw-r--r--include/asm-sh/kgdb.h8
8 files changed, 117 insertions, 89 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 2f6d2bcb1c93..ff30d7f58043 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -6,7 +6,8 @@ extra-y := head.o init_task.o vmlinux.lds
6 6
7obj-y := process.o signal.o traps.o irq.o \ 7obj-y := process.o signal.o traps.o irq.o \
8 ptrace.o setup.o time.o sys_sh.o semaphore.o \ 8 ptrace.o setup.o time.o sys_sh.o semaphore.o \
9 io.o io_generic.o sh_ksyms.o syscalls.o 9 io.o io_generic.o sh_ksyms.o syscalls.o \
10 debugtraps.o
10 11
11obj-y += cpu/ timers/ 12obj-y += cpu/ timers/
12obj-$(CONFIG_VSYSCALL) += vsyscall/ 13obj-$(CONFIG_VSYSCALL) += vsyscall/
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S
index d51fa5e9904a..8de48102ac85 100644
--- a/arch/sh/kernel/cpu/sh2/entry.S
+++ b/arch/sh/kernel/cpu/sh2/entry.S
@@ -206,7 +206,7 @@ trap_entry:
206 206
207#if defined(CONFIG_SH_STANDARD_BIOS) 207#if defined(CONFIG_SH_STANDARD_BIOS)
208 /* Unwind the stack and jmp to the debug entry */ 208 /* Unwind the stack and jmp to the debug entry */
209debug_kernel_fw: 209ENTRY(sh_bios_handler)
210 mov r15,r0 210 mov r15,r0
211 add #(22-4)*4-4,r0 211 add #(22-4)*4-4,r0
212 ldc.l @r0+,gbr 212 ldc.l @r0+,gbr
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index 8c0dc2700c69..014ac37ca16a 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -173,7 +173,7 @@ call_dae:
173 173
174#if defined(CONFIG_SH_STANDARD_BIOS) 174#if defined(CONFIG_SH_STANDARD_BIOS)
175 /* Unwind the stack and jmp to the debug entry */ 175 /* Unwind the stack and jmp to the debug entry */
176debug_kernel_fw: 176ENTRY(sh_bios_handler)
177 mov.l @r15+, r0 177 mov.l @r15+, r0
178 mov.l @r15+, r1 178 mov.l @r15+, r1
179 mov.l @r15+, r2 179 mov.l @r15+, r2
diff --git a/arch/sh/kernel/debugtraps.S b/arch/sh/kernel/debugtraps.S
new file mode 100644
index 000000000000..13b66746410a
--- /dev/null
+++ b/arch/sh/kernel/debugtraps.S
@@ -0,0 +1,41 @@
1/*
2 * arch/sh/kernel/debugtraps.S
3 *
4 * Debug trap jump tables for SuperH
5 *
6 * Copyright (C) 2006 Paul Mundt
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12#include <linux/sys.h>
13#include <linux/linkage.h>
14
15#if !defined(CONFIG_SH_KGDB)
16#define kgdb_handle_exception debug_trap_handler
17#endif
18
19#if !defined(CONFIG_SH_STANDARD_BIOS)
20#define sh_bios_handler debug_trap_handler
21#endif
22
23 .data
24
25ENTRY(debug_trap_table)
26 .long debug_trap_handler /* 0x30 */
27 .long debug_trap_handler /* 0x31 */
28 .long debug_trap_handler /* 0x32 */
29 .long debug_trap_handler /* 0x33 */
30 .long debug_trap_handler /* 0x34 */
31 .long debug_trap_handler /* 0x35 */
32 .long debug_trap_handler /* 0x36 */
33 .long debug_trap_handler /* 0x37 */
34 .long debug_trap_handler /* 0x38 */
35 .long debug_trap_handler /* 0x39 */
36 .long debug_trap_handler /* 0x3a */
37 .long debug_trap_handler /* 0x3b */
38 .long kgdb_handle_exception /* 0x3c */
39 .long debug_trap_handler /* 0x3d */
40 .long bug_trap_handler /* 0x3e */
41 .long sh_bios_handler /* 0x3f */
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index fc279aeb73ab..ab4ebb856c2a 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -54,79 +54,24 @@
54# define resume_kernel __restore_all 54# define resume_kernel __restore_all
55#endif 55#endif
56 56
57#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
58! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present.
59! If both are configured, handle the debug traps (breakpoints) in SW,
60! but still allow BIOS traps to FW.
61
62 .align 2
63debug_kernel:
64#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB)
65 /* Force BIOS call to FW (debug_trap put TRA in r8) */
66 mov r8,r0
67 shlr2 r0
68 cmp/eq #0x3f,r0
69 bt debug_kernel_fw
70#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */
71
72debug_enter:
73#if defined(CONFIG_SH_KGDB)
74 /* Jump to kgdb, pass stacked regs as arg */
75debug_kernel_sw:
76 mov.l 3f, r0
77 jmp @r0
78 mov r15, r4
79 .align 2
803: .long kgdb_handle_exception
81#endif /* CONFIG_SH_KGDB */
82#ifdef CONFIG_SH_STANDARD_BIOS
83 bra debug_kernel_fw
84 nop
85#endif
86#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
87
88 .align 2
89debug_trap:
90#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
91 mov r8, r0
92 shlr2 r0
93 cmp/eq #0x3f, r0 ! sh_bios() trap
94 bf 1f
95#ifdef CONFIG_SH_KGDB
96 cmp/eq #0xff, r0 ! XXX: KGDB trap, fix for SH-2.
97 bf 1f
98#endif
99 mov #OFF_SR, r0
100 mov.l @(r0,r15), r0 ! get status register
101 shll r0
102 shll r0 ! kernel space?
103 bt/s debug_kernel
1041:
105#endif
106 mov.l @r15, r0 ! Restore R0 value
107 mov.l 1f, r8
108 jmp @r8
109 nop
110 57
111 .align 2 58 .align 2
112ENTRY(exception_error) 59ENTRY(exception_error)
113 ! 60 !
114#ifdef CONFIG_TRACE_IRQFLAGS 61#ifdef CONFIG_TRACE_IRQFLAGS
115 mov.l 3f, r0 62 mov.l 2f, r0
116 jsr @r0 63 jsr @r0
117 nop 64 nop
118#endif 65#endif
119 sti 66 sti
120 mov.l 2f, r0 67 mov.l 1f, r0
121 jmp @r0 68 jmp @r0
122 nop 69 nop
123 70
124!
125 .align 2 71 .align 2
1261: .long break_point_trap_software 721: .long do_exception_error
1272: .long do_exception_error
128#ifdef CONFIG_TRACE_IRQFLAGS 73#ifdef CONFIG_TRACE_IRQFLAGS
1293: .long trace_hardirqs_on 742: .long trace_hardirqs_on
130#endif 75#endif
131 76
132 .align 2 77 .align 2
@@ -331,16 +276,31 @@ __restore_all:
3311: .long restore_all 2761: .long restore_all
332 277
333 .align 2 278 .align 2
334not_syscall_tra:
335 bra debug_trap
336 nop
337
338 .align 2
339syscall_badsys: ! Bad syscall number 279syscall_badsys: ! Bad syscall number
340 mov #-ENOSYS, r0 280 mov #-ENOSYS, r0
341 bra resume_userspace 281 bra resume_userspace
342 mov.l r0, @(OFF_R0,r15) ! Return value 282 mov.l r0, @(OFF_R0,r15) ! Return value
343 283
284/*
285 * The main debug trap handler.
286 *
287 * r8=TRA (not the trap number!)
288 *
289 * Note: This assumes that the trapa value is left in its original
290 * form (without the shlr2 shift) so the calculation for the jump
291 * call table offset remains a simple in place mask.
292 */
293debug_trap:
294 mov r8, r0
295 and #(0xf << 2), r0
296 mov.l 1f, r8
297 add r0, r8
298 mov.l @r8, r8
299 jmp @r8
300 nop
301
302 .align 2
3031: .long debug_trap_table
344 304
345/* 305/*
346 * Syscall interface: 306 * Syscall interface:
@@ -348,17 +308,19 @@ syscall_badsys: ! Bad syscall number
348 * Syscall #: R3 308 * Syscall #: R3
349 * Arguments #0 to #3: R4--R7 309 * Arguments #0 to #3: R4--R7
350 * Arguments #4 to #6: R0, R1, R2 310 * Arguments #4 to #6: R0, R1, R2
351 * TRA: (number of arguments + 0x10) x 4 311 * TRA: (number of arguments + ABI revision) x 4
352 * 312 *
353 * This code also handles delegating other traps to the BIOS/gdb stub 313 * This code also handles delegating other traps to the BIOS/gdb stub
354 * according to: 314 * according to:
355 * 315 *
356 * Trap number 316 * Trap number
357 * (TRA>>2) Purpose 317 * (TRA>>2) Purpose
358 * -------- ------- 318 * -------- -------
359 * 0x0-0xf old syscall ABI 319 * 0x00-0x0f original SH-3/4 syscall ABI (not in general use).
360 * 0x10-0x1f new syscall ABI 320 * 0x10-0x1f general SH-3/4 syscall ABI.
361 * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. 321 * 0x20-0x2f syscall ABI for SH-2 parts.
322 * 0x30-0x3f debug traps used by the kernel.
323 * 0x40-0xff Not supported by all parts, so left unhandled.
362 * 324 *
363 * Note: When we're first called, the TRA value must be shifted 325 * Note: When we're first called, the TRA value must be shifted
364 * right 2 bits in order to get the value that was used as the "trapa" 326 * right 2 bits in order to get the value that was used as the "trapa"
@@ -375,17 +337,22 @@ ret_from_fork:
375 nop 337 nop
376 .align 2 338 .align 2
3771: .long schedule_tail 3391: .long schedule_tail
378 ! 340
341/*
342 * The poorly named main trapa decode and dispatch routine, for
343 * system calls and debug traps through their respective jump tables.
344 */
379ENTRY(system_call) 345ENTRY(system_call)
380#if !defined(CONFIG_CPU_SH2) 346#if !defined(CONFIG_CPU_SH2)
381 mov.l 1f, r9 347 mov.l 1f, r9
382 mov.l @r9, r8 ! Read from TRA (Trap Address) Register 348 mov.l @r9, r8 ! Read from TRA (Trap Address) Register
383#endif 349#endif
384 ! 350 /*
385 ! Is the trap argument >= 0x20? (TRA will be >= 0x80) 351 * Check the trap type
386 mov #0x7f, r9 352 */
353 mov #((0x20 << 2) - 1), r9
387 cmp/hi r9, r8 354 cmp/hi r9, r8
388 bt/s not_syscall_tra 355 bt/s debug_trap ! it's a debug trap..
389 mov #OFF_TRA, r9 356 mov #OFF_TRA, r9
390 add r15, r9 357 add r15, r9
391 mov.l r8, @r9 ! set TRA value to tra 358 mov.l r8, @r9 ! set TRA value to tra
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
index 9c6315f0335d..d8927d85492e 100644
--- a/arch/sh/kernel/kgdb_stub.c
+++ b/arch/sh/kernel/kgdb_stub.c
@@ -1323,8 +1323,11 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
1323} 1323}
1324 1324
1325/* There has been an exception, most likely a breakpoint. */ 1325/* There has been an exception, most likely a breakpoint. */
1326void kgdb_handle_exception(struct pt_regs *regs) 1326asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
1327 unsigned long r6, unsigned long r7,
1328 struct pt_regs __regs)
1327{ 1329{
1330 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
1328 int excep_code, vbr_val; 1331 int excep_code, vbr_val;
1329 int count; 1332 int count;
1330 int trapa_value = ctrl_inl(TRA); 1333 int trapa_value = ctrl_inl(TRA);
@@ -1368,8 +1371,6 @@ void kgdb_handle_exception(struct pt_regs *regs)
1368 1371
1369 vbr_val = trap_registers.vbr; 1372 vbr_val = trap_registers.vbr;
1370 asm("ldc %0, vbr": :"r"(vbr_val)); 1373 asm("ldc %0, vbr": :"r"(vbr_val));
1371
1372 return;
1373} 1374}
1374 1375
1375/* Trigger a breakpoint by function */ 1376/* Trigger a breakpoint by function */
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 486c06e18033..cc8f306fd682 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -493,9 +493,27 @@ asmlinkage void break_point_trap(void)
493 force_sig(SIGTRAP, current); 493 force_sig(SIGTRAP, current);
494} 494}
495 495
496asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5, 496/*
497 unsigned long r6, unsigned long r7, 497 * Generic trap handler.
498 struct pt_regs __regs) 498 */
499asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
500 unsigned long r6, unsigned long r7,
501 struct pt_regs __regs)
502{
503 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
504
505 /* Rewind */
506 regs->pc -= 2;
507
508 force_sig(SIGTRAP, current);
509}
510
511/*
512 * Special handler for BUG() traps.
513 */
514asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
515 unsigned long r6, unsigned long r7,
516 struct pt_regs __regs)
499{ 517{
500 struct pt_regs *regs = RELOC_HIDE(&__regs, 0); 518 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
501 519
diff --git a/include/asm-sh/kgdb.h b/include/asm-sh/kgdb.h
index 7b26f53fe343..0095c665d272 100644
--- a/include/asm-sh/kgdb.h
+++ b/include/asm-sh/kgdb.h
@@ -85,10 +85,10 @@ extern int setjmp(jmp_buf __jmpb);
85#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__) 85#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__)
86 86
87/* Forced breakpoint */ 87/* Forced breakpoint */
88#define BREAKPOINT() do { \ 88#define BREAKPOINT() \
89 if (kgdb_enabled) { \ 89do { \
90 asm volatile("trapa #0xff"); \ 90 if (kgdb_enabled) \
91 } \ 91 __asm__ __volatile__("trapa #0x3c"); \
92} while (0) 92} while (0)
93 93
94/* KGDB should be able to flush all kernel text space */ 94/* KGDB should be able to flush all kernel text space */