diff options
-rw-r--r-- | arch/sh/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/entry.S | 2 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/entry.S | 2 | ||||
-rw-r--r-- | arch/sh/kernel/debugtraps.S | 41 | ||||
-rw-r--r-- | arch/sh/kernel/entry-common.S | 119 | ||||
-rw-r--r-- | arch/sh/kernel/kgdb_stub.c | 7 | ||||
-rw-r--r-- | arch/sh/kernel/process.c | 24 | ||||
-rw-r--r-- | include/asm-sh/kgdb.h | 8 |
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 | ||
7 | obj-y := process.o signal.o traps.o irq.o \ | 7 | obj-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 | ||
11 | obj-y += cpu/ timers/ | 12 | obj-y += cpu/ timers/ |
12 | obj-$(CONFIG_VSYSCALL) += vsyscall/ | 13 | obj-$(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 */ |
209 | debug_kernel_fw: | 209 | ENTRY(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 */ |
176 | debug_kernel_fw: | 176 | ENTRY(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 | |||
25 | ENTRY(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 | ||
63 | debug_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 | |||
72 | debug_enter: | ||
73 | #if defined(CONFIG_SH_KGDB) | ||
74 | /* Jump to kgdb, pass stacked regs as arg */ | ||
75 | debug_kernel_sw: | ||
76 | mov.l 3f, r0 | ||
77 | jmp @r0 | ||
78 | mov r15, r4 | ||
79 | .align 2 | ||
80 | 3: .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 | ||
89 | debug_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 | ||
104 | 1: | ||
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 |
112 | ENTRY(exception_error) | 59 | ENTRY(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 |
126 | 1: .long break_point_trap_software | 72 | 1: .long do_exception_error |
127 | 2: .long do_exception_error | ||
128 | #ifdef CONFIG_TRACE_IRQFLAGS | 73 | #ifdef CONFIG_TRACE_IRQFLAGS |
129 | 3: .long trace_hardirqs_on | 74 | 2: .long trace_hardirqs_on |
130 | #endif | 75 | #endif |
131 | 76 | ||
132 | .align 2 | 77 | .align 2 |
@@ -331,16 +276,31 @@ __restore_all: | |||
331 | 1: .long restore_all | 276 | 1: .long restore_all |
332 | 277 | ||
333 | .align 2 | 278 | .align 2 |
334 | not_syscall_tra: | ||
335 | bra debug_trap | ||
336 | nop | ||
337 | |||
338 | .align 2 | ||
339 | syscall_badsys: ! Bad syscall number | 279 | syscall_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 | */ | ||
293 | debug_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 | ||
303 | 1: .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 |
377 | 1: .long schedule_tail | 339 | 1: .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 | */ | ||
379 | ENTRY(system_call) | 345 | ENTRY(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. */ |
1326 | void kgdb_handle_exception(struct pt_regs *regs) | 1326 | asmlinkage 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 | ||
496 | asmlinkage 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 | */ |
499 | asmlinkage 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 | */ | ||
514 | asmlinkage 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) { \ | 89 | do { \ |
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 */ |