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>
This commit is contained in:
parent
ec2f9d1331
commit
f413d0d9fa
|
@ -6,7 +6,8 @@ extra-y := head.o init_task.o vmlinux.lds
|
|||
|
||||
obj-y := process.o signal.o traps.o irq.o \
|
||||
ptrace.o setup.o time.o sys_sh.o semaphore.o \
|
||||
io.o io_generic.o sh_ksyms.o syscalls.o
|
||||
io.o io_generic.o sh_ksyms.o syscalls.o \
|
||||
debugtraps.o
|
||||
|
||||
obj-y += cpu/ timers/
|
||||
obj-$(CONFIG_VSYSCALL) += vsyscall/
|
||||
|
|
|
@ -206,7 +206,7 @@ trap_entry:
|
|||
|
||||
#if defined(CONFIG_SH_STANDARD_BIOS)
|
||||
/* Unwind the stack and jmp to the debug entry */
|
||||
debug_kernel_fw:
|
||||
ENTRY(sh_bios_handler)
|
||||
mov r15,r0
|
||||
add #(22-4)*4-4,r0
|
||||
ldc.l @r0+,gbr
|
||||
|
|
|
@ -173,7 +173,7 @@ call_dae:
|
|||
|
||||
#if defined(CONFIG_SH_STANDARD_BIOS)
|
||||
/* Unwind the stack and jmp to the debug entry */
|
||||
debug_kernel_fw:
|
||||
ENTRY(sh_bios_handler)
|
||||
mov.l @r15+, r0
|
||||
mov.l @r15+, r1
|
||||
mov.l @r15+, r2
|
||||
|
|
41
arch/sh/kernel/debugtraps.S
Normal file
41
arch/sh/kernel/debugtraps.S
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* arch/sh/kernel/debugtraps.S
|
||||
*
|
||||
* Debug trap jump tables for SuperH
|
||||
*
|
||||
* Copyright (C) 2006 Paul Mundt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/sys.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#if !defined(CONFIG_SH_KGDB)
|
||||
#define kgdb_handle_exception debug_trap_handler
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_SH_STANDARD_BIOS)
|
||||
#define sh_bios_handler debug_trap_handler
|
||||
#endif
|
||||
|
||||
.data
|
||||
|
||||
ENTRY(debug_trap_table)
|
||||
.long debug_trap_handler /* 0x30 */
|
||||
.long debug_trap_handler /* 0x31 */
|
||||
.long debug_trap_handler /* 0x32 */
|
||||
.long debug_trap_handler /* 0x33 */
|
||||
.long debug_trap_handler /* 0x34 */
|
||||
.long debug_trap_handler /* 0x35 */
|
||||
.long debug_trap_handler /* 0x36 */
|
||||
.long debug_trap_handler /* 0x37 */
|
||||
.long debug_trap_handler /* 0x38 */
|
||||
.long debug_trap_handler /* 0x39 */
|
||||
.long debug_trap_handler /* 0x3a */
|
||||
.long debug_trap_handler /* 0x3b */
|
||||
.long kgdb_handle_exception /* 0x3c */
|
||||
.long debug_trap_handler /* 0x3d */
|
||||
.long bug_trap_handler /* 0x3e */
|
||||
.long sh_bios_handler /* 0x3f */
|
|
@ -54,79 +54,24 @@
|
|||
# define resume_kernel __restore_all
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
|
||||
! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present.
|
||||
! If both are configured, handle the debug traps (breakpoints) in SW,
|
||||
! but still allow BIOS traps to FW.
|
||||
|
||||
.align 2
|
||||
debug_kernel:
|
||||
#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB)
|
||||
/* Force BIOS call to FW (debug_trap put TRA in r8) */
|
||||
mov r8,r0
|
||||
shlr2 r0
|
||||
cmp/eq #0x3f,r0
|
||||
bt debug_kernel_fw
|
||||
#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */
|
||||
|
||||
debug_enter:
|
||||
#if defined(CONFIG_SH_KGDB)
|
||||
/* Jump to kgdb, pass stacked regs as arg */
|
||||
debug_kernel_sw:
|
||||
mov.l 3f, r0
|
||||
jmp @r0
|
||||
mov r15, r4
|
||||
.align 2
|
||||
3: .long kgdb_handle_exception
|
||||
#endif /* CONFIG_SH_KGDB */
|
||||
#ifdef CONFIG_SH_STANDARD_BIOS
|
||||
bra debug_kernel_fw
|
||||
nop
|
||||
#endif
|
||||
#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
|
||||
|
||||
.align 2
|
||||
debug_trap:
|
||||
#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
|
||||
mov r8, r0
|
||||
shlr2 r0
|
||||
cmp/eq #0x3f, r0 ! sh_bios() trap
|
||||
bf 1f
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
cmp/eq #0xff, r0 ! XXX: KGDB trap, fix for SH-2.
|
||||
bf 1f
|
||||
#endif
|
||||
mov #OFF_SR, r0
|
||||
mov.l @(r0,r15), r0 ! get status register
|
||||
shll r0
|
||||
shll r0 ! kernel space?
|
||||
bt/s debug_kernel
|
||||
1:
|
||||
#endif
|
||||
mov.l @r15, r0 ! Restore R0 value
|
||||
mov.l 1f, r8
|
||||
jmp @r8
|
||||
nop
|
||||
|
||||
.align 2
|
||||
ENTRY(exception_error)
|
||||
!
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
mov.l 3f, r0
|
||||
mov.l 2f, r0
|
||||
jsr @r0
|
||||
nop
|
||||
#endif
|
||||
sti
|
||||
mov.l 2f, r0
|
||||
mov.l 1f, r0
|
||||
jmp @r0
|
||||
nop
|
||||
|
||||
!
|
||||
.align 2
|
||||
1: .long break_point_trap_software
|
||||
2: .long do_exception_error
|
||||
1: .long do_exception_error
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
3: .long trace_hardirqs_on
|
||||
2: .long trace_hardirqs_on
|
||||
#endif
|
||||
|
||||
.align 2
|
||||
|
@ -330,17 +275,32 @@ __restore_all:
|
|||
.align 2
|
||||
1: .long restore_all
|
||||
|
||||
.align 2
|
||||
not_syscall_tra:
|
||||
bra debug_trap
|
||||
nop
|
||||
|
||||
.align 2
|
||||
syscall_badsys: ! Bad syscall number
|
||||
mov #-ENOSYS, r0
|
||||
bra resume_userspace
|
||||
mov.l r0, @(OFF_R0,r15) ! Return value
|
||||
|
||||
|
||||
/*
|
||||
* The main debug trap handler.
|
||||
*
|
||||
* r8=TRA (not the trap number!)
|
||||
*
|
||||
* Note: This assumes that the trapa value is left in its original
|
||||
* form (without the shlr2 shift) so the calculation for the jump
|
||||
* call table offset remains a simple in place mask.
|
||||
*/
|
||||
debug_trap:
|
||||
mov r8, r0
|
||||
and #(0xf << 2), r0
|
||||
mov.l 1f, r8
|
||||
add r0, r8
|
||||
mov.l @r8, r8
|
||||
jmp @r8
|
||||
nop
|
||||
|
||||
.align 2
|
||||
1: .long debug_trap_table
|
||||
|
||||
/*
|
||||
* Syscall interface:
|
||||
|
@ -348,17 +308,19 @@ syscall_badsys: ! Bad syscall number
|
|||
* Syscall #: R3
|
||||
* Arguments #0 to #3: R4--R7
|
||||
* Arguments #4 to #6: R0, R1, R2
|
||||
* TRA: (number of arguments + 0x10) x 4
|
||||
* TRA: (number of arguments + ABI revision) x 4
|
||||
*
|
||||
* This code also handles delegating other traps to the BIOS/gdb stub
|
||||
* according to:
|
||||
*
|
||||
* Trap number
|
||||
* (TRA>>2) Purpose
|
||||
* -------- -------
|
||||
* 0x0-0xf old syscall ABI
|
||||
* 0x10-0x1f new syscall ABI
|
||||
* 0x20-0xff delegated through debug_trap to BIOS/gdb stub.
|
||||
* (TRA>>2) Purpose
|
||||
* -------- -------
|
||||
* 0x00-0x0f original SH-3/4 syscall ABI (not in general use).
|
||||
* 0x10-0x1f general SH-3/4 syscall ABI.
|
||||
* 0x20-0x2f syscall ABI for SH-2 parts.
|
||||
* 0x30-0x3f debug traps used by the kernel.
|
||||
* 0x40-0xff Not supported by all parts, so left unhandled.
|
||||
*
|
||||
* Note: When we're first called, the TRA value must be shifted
|
||||
* right 2 bits in order to get the value that was used as the "trapa"
|
||||
|
@ -375,17 +337,22 @@ ret_from_fork:
|
|||
nop
|
||||
.align 2
|
||||
1: .long schedule_tail
|
||||
!
|
||||
|
||||
/*
|
||||
* The poorly named main trapa decode and dispatch routine, for
|
||||
* system calls and debug traps through their respective jump tables.
|
||||
*/
|
||||
ENTRY(system_call)
|
||||
#if !defined(CONFIG_CPU_SH2)
|
||||
mov.l 1f, r9
|
||||
mov.l @r9, r8 ! Read from TRA (Trap Address) Register
|
||||
#endif
|
||||
!
|
||||
! Is the trap argument >= 0x20? (TRA will be >= 0x80)
|
||||
mov #0x7f, r9
|
||||
/*
|
||||
* Check the trap type
|
||||
*/
|
||||
mov #((0x20 << 2) - 1), r9
|
||||
cmp/hi r9, r8
|
||||
bt/s not_syscall_tra
|
||||
bt/s debug_trap ! it's a debug trap..
|
||||
mov #OFF_TRA, r9
|
||||
add r15, r9
|
||||
mov.l r8, @r9 ! set TRA value to tra
|
||||
|
|
|
@ -1323,8 +1323,11 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
|
|||
}
|
||||
|
||||
/* There has been an exception, most likely a breakpoint. */
|
||||
void kgdb_handle_exception(struct pt_regs *regs)
|
||||
asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
|
||||
unsigned long r6, unsigned long r7,
|
||||
struct pt_regs __regs)
|
||||
{
|
||||
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
|
||||
int excep_code, vbr_val;
|
||||
int count;
|
||||
int trapa_value = ctrl_inl(TRA);
|
||||
|
@ -1368,8 +1371,6 @@ void kgdb_handle_exception(struct pt_regs *regs)
|
|||
|
||||
vbr_val = trap_registers.vbr;
|
||||
asm("ldc %0, vbr": :"r"(vbr_val));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Trigger a breakpoint by function */
|
||||
|
|
|
@ -493,9 +493,27 @@ asmlinkage void break_point_trap(void)
|
|||
force_sig(SIGTRAP, current);
|
||||
}
|
||||
|
||||
asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5,
|
||||
unsigned long r6, unsigned long r7,
|
||||
struct pt_regs __regs)
|
||||
/*
|
||||
* Generic trap handler.
|
||||
*/
|
||||
asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
|
||||
unsigned long r6, unsigned long r7,
|
||||
struct pt_regs __regs)
|
||||
{
|
||||
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
|
||||
|
||||
/* Rewind */
|
||||
regs->pc -= 2;
|
||||
|
||||
force_sig(SIGTRAP, current);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special handler for BUG() traps.
|
||||
*/
|
||||
asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
|
||||
unsigned long r6, unsigned long r7,
|
||||
struct pt_regs __regs)
|
||||
{
|
||||
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
|
||||
|
||||
|
|
|
@ -85,10 +85,10 @@ extern int setjmp(jmp_buf __jmpb);
|
|||
#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__)
|
||||
|
||||
/* Forced breakpoint */
|
||||
#define BREAKPOINT() do { \
|
||||
if (kgdb_enabled) { \
|
||||
asm volatile("trapa #0xff"); \
|
||||
} \
|
||||
#define BREAKPOINT() \
|
||||
do { \
|
||||
if (kgdb_enabled) \
|
||||
__asm__ __volatile__("trapa #0x3c"); \
|
||||
} while (0)
|
||||
|
||||
/* KGDB should be able to flush all kernel text space */
|
||||
|
|
Loading…
Reference in a new issue