Commit f413d0d9 authored by Paul Mundt's avatar Paul Mundt
Browse files

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: default avatarPaul Mundt <lethal@linux-sh.org>
parent ec2f9d13
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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/
+1 −1
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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 */
+43 −76
Original line number Diff line number Diff line
@@ -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,7 +308,7 @@ 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:
@@ -356,9 +316,11 @@ syscall_badsys: ! Bad syscall number
 * 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.
 * 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
Loading