summaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-02-23 07:14:02 +0000
committerPaul Mundt <lethal@linux-sh.org>2009-02-27 16:26:10 +0900
commit1d015cf02a1fd46385c03cf3ce8958dbea705dd3 (patch)
tree833e2ab294be74d7ecb3512a24bfefbc86189c59 /arch/sh/kernel
parentb233b28eac0cc37d07c2d007ea08c86c778c5af4 (diff)
sh: shared register saving code for sh3/sh4/sh4a
This patch reworks the sh3/sh4/sh4a register saving code in the following ways: - break out prepare_stack_save_dsp() from handle_exception() - break out save_regs() from handle_exception() - the register saving order is unchanged - align new functions to fit in cache lines - separate exception code from interrupt code - keep main code flow in a single cache line per exception vector - use bsr/rts for regular functions (save pr first) - keep data in one shared cache line (exception_data) - document the functions - tie in the hp6xx code Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S273
1 files changed, 147 insertions, 126 deletions
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index b4106d0c68e..f3db143e70b 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -16,6 +16,7 @@
#include <asm/unistd.h>
#include <cpu/mmu_context.h>
#include <asm/page.h>
+#include <asm/cache.h>
! NOTE:
! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -294,7 +295,7 @@ skip_restore:
mov #0xf0, k1
extu.b k1, k1
not k1, k1
- and k1, k2 ! Mask orignal SR value
+ and k1, k2 ! Mask original SR value
!
mov k3, k0 ! Calculate IMASK-bits
shlr2 k0
@@ -336,81 +337,53 @@ skip_restore:
ENTRY(vbr_base)
.long 0
!
+! 0x100: General exception vector
+!
.balign 256,0,256
general_exception:
- mov.l 1f, k2
- mov.l 2f, k3
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
- mov.l @k2, k2
+#ifndef CONFIG_CPU_SUBTYPE_SHX3
+ bra handle_exception
+ sts pr, k3 ! save original pr value in k3
+#else
+ mov.l 1f, k4
+ mov.l @k4, k4
! Is EXPEVT larger than 0x800?
mov #0x8, k0
shll8 k0
- cmp/hs k0, k2
+ cmp/hs k0, k4
bf 0f
! then add 0x580 (k2 is 0xd80 or 0xda0)
mov #0x58, k0
shll2 k0
shll2 k0
- add k0, k2
+ add k0, k4
0:
- bra handle_exception
+ ! Setup stack and save DSP context (k0 contains original r15 on return)
+ bsr prepare_stack_save_dsp
nop
-#else
- bra handle_exception
- mov.l @k2, k2
-#endif
- .align 2
-1: .long EXPEVT
-2: .long ret_from_exception
-!
-!
- .balign 1024,0,1024
-tlb_miss:
- mov.l 1f, k2
- mov.l 4f, k3
- bra handle_exception
- mov.l @k2, k2
-!
- .balign 512,0,512
-interrupt:
- mov.l 3f, k3
-#if defined(CONFIG_KGDB)
- mov.l 2f, k2
- ! Debounce (filter nested NMI)
- mov.l @k2, k0
- mov.l 5f, k1
- cmp/eq k1, k0
- bf 0f
- mov.l 6f, k1
- tas.b @k1
- bt 0f
- rte
+ ! Save registers / Switch to bank 0
+ bsr save_regs ! needs original pr value in k3
+ mov.l k4, k2 ! keep vector in k2
+
+ bra handle_exception_special
nop
- .align 2
-2: .long INTEVT
-5: .long NMI_VEC
-6: .long in_nmi
-0:
-#endif /* defined(CONFIG_KGDB) */
- bra handle_exception
- mov #-1, k2 ! interrupt exception marker
.align 2
1: .long EXPEVT
-3: .long ret_from_irq
-4: .long ret_from_exception
+#endif
-!
-!
- .align 2
-ENTRY(handle_exception)
- ! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
- ! save all registers onto stack.
- !
+! prepare_stack_save_dsp()
+! - roll back gRB
+! - switch to kernel stack
+! - save DSP
+! k0 returns original sp (after roll back)
+! k1 trashed
+! k2 trashed
+prepare_stack_save_dsp:
#ifdef CONFIG_GUSA
! Check for roll back gRB (User and Kernel)
mov r15, k0
@@ -430,7 +403,7 @@ ENTRY(handle_exception)
2: mov k1, r15 ! SP = r1
1:
#endif
-
+ ! Switch to kernel stack if needed
stc ssr, k0 ! Is it from kernel space?
shll k0 ! Check MD bit (bit30) by shifting it into...
shll k0 ! ...the T bit
@@ -443,18 +416,17 @@ ENTRY(handle_exception)
add current, k1
mov k1, r15 ! change to kernel stack
!
-1: mov.l 2f, k1
- !
+1:
#ifdef CONFIG_SH_DSP
- mov.l r2, @-r15 ! Save r2, we need another reg
- stc sr, k4
- mov.l 1f, r2
- tst r2, k4 ! Check if in DSP mode
- mov.l @r15+, r2 ! Restore r2 now
+ ! Save DSP context if needed
+ stc sr, k1
+ mov #0x10, k2
+ shll8 k2 ! DSP=1 (0x00001000)
+ tst k2, k1 ! Check if in DSP mode (passed in k2)
bt/s skip_save
- mov #0, k4 ! Set marker for no stack frame
+ mov #0, k1 ! Set marker for no stack frame
- mov r2, k4 ! Backup r2 (in k4) for later
+ mov k2, k1 ! Save has-frame marker
! Save DSP registers on stack
stc.l mod, @-r15
@@ -473,35 +445,73 @@ ENTRY(handle_exception)
! as we're not at all interested in supporting ancient toolchains at
! this point. -- PFM.
- mov r15, r2
+ mov r15, k2
.word 0xf653 ! movs.l a1, @-r2
.word 0xf6f3 ! movs.l a0g, @-r2
.word 0xf6d3 ! movs.l a1g, @-r2
.word 0xf6c3 ! movs.l m0, @-r2
.word 0xf6e3 ! movs.l m1, @-r2
- mov r2, r15
+ mov k2, r15
- mov k4, r2 ! Restore r2
- mov.l 1f, k4 ! Force DSP stack frame
skip_save:
- mov.l k4, @-r15 ! Push DSP mode marker onto stack
+ mov.l k1, @-r15 ! Push DSP mode marker onto stack
#endif
- ! Save the user registers on the stack.
- mov.l k2, @-r15 ! EXPEVT
+ rts
+ nop
+!
+! 0x400: Instruction and Data TLB miss exception vector
+!
+ .balign 1024,0,1024
+tlb_miss:
+ sts pr, k3 ! save original pr value in k3
- mov #-1, k4
- mov.l k4, @-r15 ! set TRA (default: -1)
- !
+handle_exception:
+ ! Setup stack and save DSP context (k0 contains original r15 on return)
+ bsr prepare_stack_save_dsp
+ nop
+
+ ! Save registers / Switch to bank 0
+ mov.l 5f, k2 ! vector register address
+ bsr save_regs ! needs original pr value in k3
+ mov.l @k2, k2 ! read out vector and keep in k2
+
+handle_exception_special:
+ ! Setup return address and jump to exception handler
+ mov.l 7f, r9 ! fetch return address
+ stc r2_bank, r0 ! k2 (vector)
+ mov.l 6f, r10
+ shlr2 r0
+ shlr r0
+ mov.l @(r0, r10), r10
+ jmp @r10
+ lds r9, pr ! put return address in pr
+
+ .align L1_CACHE_SHIFT
+
+! save_regs()
+! - save vector, default tra, macl, mach, gbr, ssr, pr* and spc on the stack
+! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
+! - switch bank
+! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
+! k0 contains original stack pointer*
+! k1 trashed
+! k2 passes vector (EXPEVT)
+! k3 passes original pr*
+! k4 trashed
+! BL=1 on entry, on exit BL=0.
+
+save_regs:
+ mov #-1, r1
+ mov.l k2, @-r15 ! vector in k2
+ mov.l k1, @-r15 ! set TRA (default: -1)
sts.l macl, @-r15
sts.l mach, @-r15
stc.l gbr, @-r15
stc.l ssr, @-r15
- sts.l pr, @-r15
+ mov.l k3, @-r15 ! original pr in k3
stc.l spc, @-r15
- !
- lds k3, pr ! Set the return address to pr
- !
- mov.l k0, @-r15 ! save orignal stack
+
+ mov.l k0, @-r15 ! original stack pointer in k0
mov.l r14, @-r15
mov.l r13, @-r15
mov.l r12, @-r15
@@ -509,13 +519,15 @@ skip_save:
mov.l r10, @-r15
mov.l r9, @-r15
mov.l r8, @-r15
- !
- stc sr, r8 ! Back to normal register bank, and
- or k1, r8 ! Block all interrupts
- mov.l 3f, k1
- and k1, r8 ! ...
- ldc r8, sr ! ...changed here.
- !
+
+ mov.l 0f, k3 ! SR bits to set in k3
+ mov.l 1f, k4 ! SR bits to clear in k4
+
+ stc sr, r8
+ or k3, r8
+ and k4, r8
+ ldc r8, sr
+
mov.l r7, @-r15
mov.l r6, @-r15
mov.l r5, @-r15
@@ -523,52 +535,61 @@ skip_save:
mov.l r3, @-r15
mov.l r2, @-r15
mov.l r1, @-r15
- mov.l r0, @-r15
-
- /*
- * This gets a bit tricky.. in the INTEVT case we don't want to use
- * the VBR offset as a destination in the jump call table, since all
- * of the destinations are the same. In this case, (interrupt) sets
- * a marker in r2 (now r2_bank since SR.RB changed), which we check
- * to determine the exception type. For all other exceptions, we
- * forcibly read EXPEVT from memory and fix up the jump address, in
- * the interrupt exception case we jump to do_IRQ() and defer the
- * INTEVT read until there. As a bonus, we can also clean up the SR.RB
- * checks that do_IRQ() was doing..
- */
- stc r2_bank, r8
- cmp/pz r8
- bf interrupt_exception
- shlr2 r8
- shlr r8
- mov.l 4f, r9
- add r8, r9
- mov.l @r9, r9
- jmp @r9
- nop
rts
- nop
+ mov.l r0, @-r15
+!
+! 0x600: Interrupt / NMI vector
+!
+ .balign 512,0,512
+ENTRY(handle_interrupt)
+#if defined(CONFIG_KGDB)
+ mov.l 2f, k2
+ ! Debounce (filter nested NMI)
+ mov.l @k2, k0
+ mov.l 9f, k1
+ cmp/eq k1, k0
+ bf 11f
+ mov.l 10f, k1
+ tas.b @k1
+ bt 11f
+ rte
+ nop
.align 2
-1: .long 0x00001000 ! DSP=1
-2: .long 0x000080f0 ! FD=1, IMASK=15
-3: .long 0xcfffffff ! RB=0, BL=0
-4: .long exception_handling_table
+9: .long NMI_VEC
+10: .long in_nmi
+11:
+#endif /* defined(CONFIG_KGDB) */
+ sts pr, k3 ! save original pr value in k3
-interrupt_exception:
- mov.l 1f, r9
- mov.l 2f, r4
- mov.l @r4, r4
- jmp @r9
- mov r15, r5
- rts
+ ! Setup stack and save DSP context (k0 contains original r15 on return)
+ bsr prepare_stack_save_dsp
nop
- .align 2
-1: .long do_IRQ
-2: .long INTEVT
+ ! Save registers / Switch to bank 0
+ bsr save_regs ! needs original pr value in k3
+ mov #-1, k2 ! default vector kept in k2
+
+ ! Setup return address and jump to do_IRQ
+ mov.l 4f, r9 ! fetch return address
+ lds r9, pr ! put return address in pr
+ mov.l 2f, r4
+ mov.l 3f, r9
+ mov.l @r4, r4 ! pass INTEVT vector as arg0
+ jmp @r9
+ mov r15, r5 ! pass saved registers as arg1
- .align 2
ENTRY(exception_none)
rts
nop
+
+ .align L1_CACHE_SHIFT
+exception_data:
+0: .long 0x000080f0 ! FD=1, IMASK=15
+1: .long 0xcfffffff ! RB=0, BL=0
+2: .long INTEVT
+3: .long do_IRQ
+4: .long ret_from_irq
+5: .long EXPEVT
+6: .long exception_handling_table
+7: .long ret_from_exception