aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorKumar Gala <galak@kernel.crashing.org>2008-04-30 06:23:21 -0400
committerKumar Gala <galak@kernel.crashing.org>2008-06-02 15:56:35 -0400
commitfca622c5b21a259950a2964ceca7b6c2a23c849f (patch)
tree63e8faa227230542a7f9cc17050e42ffebd9f64f /arch/powerpc/kernel
parent369e757b65d4a5e49bae7cfaf671e784f891cfbe (diff)
[POWERPC] 40x/Book-E: Save/restore volatile exception registers
On machines with more than one exception level any system register that might be modified by the "normal" exception level needs to be saved and restored on taking a higher level exception. We already are saving and restoring ESR and DEAR. For critical level add SRR0/1. For debug level add CSRR0/1 and SRR0/1. For machine check level add DSRR0/1, CSRR0/1, and SRR0/1. On FSL Book-E parts we always save/restore the MAS registers for critical, debug, and machine check level exceptions. On 44x we always save/restore the MMUCR. Additionally, we save and restore the ksp_limit since we have to adjust it for each exception level. Signed-off-by: Kumar Gala <galak@kernel.crashing.org> Acked-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/asm-offsets.c23
-rw-r--r--arch/powerpc/kernel/entry_32.S125
-rw-r--r--arch/powerpc/kernel/head_40x.S6
-rw-r--r--arch/powerpc/kernel/head_booke.h23
4 files changed, 174 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index ec9228d687b0..8655c7670350 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -52,6 +52,10 @@
52#include <asm/iseries/alpaca.h> 52#include <asm/iseries/alpaca.h>
53#endif 53#endif
54 54
55#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
56#include "head_booke.h"
57#endif
58
55int main(void) 59int main(void)
56{ 60{
57 DEFINE(THREAD, offsetof(struct task_struct, thread)); 61 DEFINE(THREAD, offsetof(struct task_struct, thread));
@@ -242,6 +246,25 @@ int main(void)
242 DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); 246 DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
243#endif /* CONFIG_PPC64 */ 247#endif /* CONFIG_PPC64 */
244 248
249#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
250 DEFINE(EXC_LVL_SIZE, STACK_EXC_LVL_FRAME_SIZE);
251 DEFINE(MAS0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas0));
252 /* we overload MMUCR for 44x on MAS0 since they are mutually exclusive */
253 DEFINE(MMUCR, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas0));
254 DEFINE(MAS1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas1));
255 DEFINE(MAS2, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas2));
256 DEFINE(MAS3, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas3));
257 DEFINE(MAS6, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas6));
258 DEFINE(MAS7, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas7));
259 DEFINE(_SRR0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, srr0));
260 DEFINE(_SRR1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, srr1));
261 DEFINE(_CSRR0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, csrr0));
262 DEFINE(_CSRR1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, csrr1));
263 DEFINE(_DSRR0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, dsrr0));
264 DEFINE(_DSRR1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, dsrr1));
265 DEFINE(SAVED_KSP_LIMIT, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, saved_ksp_limit));
266#endif
267
245 DEFINE(CLONE_VM, CLONE_VM); 268 DEFINE(CLONE_VM, CLONE_VM);
246 DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); 269 DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
247 270
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index c94aba54b5dd..fe21674d4f06 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -46,14 +46,52 @@
46#ifdef CONFIG_BOOKE 46#ifdef CONFIG_BOOKE
47 .globl mcheck_transfer_to_handler 47 .globl mcheck_transfer_to_handler
48mcheck_transfer_to_handler: 48mcheck_transfer_to_handler:
49 b transfer_to_handler_full 49 mfspr r0,SPRN_DSRR0
50 stw r0,_DSRR0(r11)
51 mfspr r0,SPRN_DSRR1
52 stw r0,_DSRR1(r11)
53 /* fall through */
50 54
51 .globl debug_transfer_to_handler 55 .globl debug_transfer_to_handler
52debug_transfer_to_handler: 56debug_transfer_to_handler:
53 b transfer_to_handler_full 57 mfspr r0,SPRN_CSRR0
58 stw r0,_CSRR0(r11)
59 mfspr r0,SPRN_CSRR1
60 stw r0,_CSRR1(r11)
61 /* fall through */
54 62
55 .globl crit_transfer_to_handler 63 .globl crit_transfer_to_handler
56crit_transfer_to_handler: 64crit_transfer_to_handler:
65#ifdef CONFIG_FSL_BOOKE
66 mfspr r0,SPRN_MAS0
67 stw r0,MAS0(r11)
68 mfspr r0,SPRN_MAS1
69 stw r0,MAS1(r11)
70 mfspr r0,SPRN_MAS2
71 stw r0,MAS2(r11)
72 mfspr r0,SPRN_MAS3
73 stw r0,MAS3(r11)
74 mfspr r0,SPRN_MAS6
75 stw r0,MAS6(r11)
76#ifdef CONFIG_PHYS_64BIT
77 mfspr r0,SPRN_MAS7
78 stw r0,MAS7(r11)
79#endif /* CONFIG_PHYS_64BIT */
80#endif /* CONFIG_FSL_BOOKE */
81#ifdef CONFIG_44x
82 mfspr r0,SPRN_MMUCR
83 stw r0,MMUCR(r11)
84#endif
85 mfspr r0,SPRN_SRR0
86 stw r0,_SRR0(r11)
87 mfspr r0,SPRN_SRR1
88 stw r0,_SRR1(r11)
89
90 mfspr r8,SPRN_SPRG3
91 lwz r0,KSP_LIMIT(r8)
92 stw r0,SAVED_KSP_LIMIT(r11)
93 rlwimi r0,r1,0,0,(31-THREAD_SHIFT)
94 stw r0,KSP_LIMIT(r8)
57 /* fall through */ 95 /* fall through */
58#endif 96#endif
59 97
@@ -64,6 +102,16 @@ crit_transfer_to_handler:
64 stw r0,GPR10(r11) 102 stw r0,GPR10(r11)
65 lwz r0,crit_r11@l(0) 103 lwz r0,crit_r11@l(0)
66 stw r0,GPR11(r11) 104 stw r0,GPR11(r11)
105 mfspr r0,SPRN_SRR0
106 stw r0,crit_srr0@l(0)
107 mfspr r0,SPRN_SRR1
108 stw r0,crit_srr1@l(0)
109
110 mfspr r8,SPRN_SPRG3
111 lwz r0,KSP_LIMIT(r8)
112 stw r0,saved_ksp_limit@l(0)
113 rlwimi r0,r1,0,0,(31-THREAD_SHIFT)
114 stw r0,KSP_LIMIT(r8)
67 /* fall through */ 115 /* fall through */
68#endif 116#endif
69 117
@@ -854,17 +902,90 @@ exc_exit_restart_end:
854 exc_lvl_rfi; \ 902 exc_lvl_rfi; \
855 b .; /* prevent prefetch past exc_lvl_rfi */ 903 b .; /* prevent prefetch past exc_lvl_rfi */
856 904
905#define RESTORE_xSRR(exc_lvl_srr0, exc_lvl_srr1) \
906 lwz r9,_##exc_lvl_srr0(r1); \
907 lwz r10,_##exc_lvl_srr1(r1); \
908 mtspr SPRN_##exc_lvl_srr0,r9; \
909 mtspr SPRN_##exc_lvl_srr1,r10;
910
911#if defined(CONFIG_FSL_BOOKE)
912#ifdef CONFIG_PHYS_64BIT
913#define RESTORE_MAS7 \
914 lwz r11,MAS7(r1); \
915 mtspr SPRN_MAS7,r11;
916#else
917#define RESTORE_MAS7
918#endif /* CONFIG_PHYS_64BIT */
919#define RESTORE_MMU_REGS \
920 lwz r9,MAS0(r1); \
921 lwz r10,MAS1(r1); \
922 lwz r11,MAS2(r1); \
923 mtspr SPRN_MAS0,r9; \
924 lwz r9,MAS3(r1); \
925 mtspr SPRN_MAS1,r10; \
926 lwz r10,MAS6(r1); \
927 mtspr SPRN_MAS2,r11; \
928 mtspr SPRN_MAS3,r9; \
929 mtspr SPRN_MAS6,r10; \
930 RESTORE_MAS7;
931#elif defined(CONFIG_44x)
932#define RESTORE_MMU_REGS \
933 lwz r9,MMUCR(r1); \
934 mtspr SPRN_MMUCR,r9;
935#else
936#define RESTORE_MMU_REGS
937#endif
938
939#ifdef CONFIG_40x
857 .globl ret_from_crit_exc 940 .globl ret_from_crit_exc
858ret_from_crit_exc: 941ret_from_crit_exc:
942 mfspr r9,SPRN_SPRG3
943 lis r10,saved_ksp_limit@ha;
944 lwz r10,saved_ksp_limit@l(r10);
945 tovirt(r9,r9);
946 stw r10,KSP_LIMIT(r9)
947 lis r9,crit_srr0@ha;
948 lwz r9,crit_srr0@l(r9);
949 lis r10,crit_srr1@ha;
950 lwz r10,crit_srr1@l(r10);
951 mtspr SPRN_SRR0,r9;
952 mtspr SPRN_SRR1,r10;
859 RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) 953 RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
954#endif /* CONFIG_40x */
860 955
861#ifdef CONFIG_BOOKE 956#ifdef CONFIG_BOOKE
957 .globl ret_from_crit_exc
958ret_from_crit_exc:
959 mfspr r9,SPRN_SPRG3
960 lwz r10,SAVED_KSP_LIMIT(r1)
961 stw r10,KSP_LIMIT(r9)
962 RESTORE_xSRR(SRR0,SRR1);
963 RESTORE_MMU_REGS;
964 RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
965
862 .globl ret_from_debug_exc 966 .globl ret_from_debug_exc
863ret_from_debug_exc: 967ret_from_debug_exc:
968 mfspr r9,SPRN_SPRG3
969 lwz r10,SAVED_KSP_LIMIT(r1)
970 stw r10,KSP_LIMIT(r9)
971 lwz r9,THREAD_INFO-THREAD(r9)
972 rlwinm r10,r1,0,0,(31-THREAD_SHIFT)
973 lwz r10,TI_PREEMPT(r10)
974 stw r10,TI_PREEMPT(r9)
975 RESTORE_xSRR(SRR0,SRR1);
976 RESTORE_xSRR(CSRR0,CSRR1);
977 RESTORE_MMU_REGS;
864 RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI) 978 RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI)
865 979
866 .globl ret_from_mcheck_exc 980 .globl ret_from_mcheck_exc
867ret_from_mcheck_exc: 981ret_from_mcheck_exc:
982 mfspr r9,SPRN_SPRG3
983 lwz r10,SAVED_KSP_LIMIT(r1)
984 stw r10,KSP_LIMIT(r9)
985 RESTORE_xSRR(SRR0,SRR1);
986 RESTORE_xSRR(CSRR0,CSRR1);
987 RESTORE_xSRR(DSRR0,DSRR1);
988 RESTORE_MMU_REGS;
868 RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) 989 RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI)
869#endif /* CONFIG_BOOKE */ 990#endif /* CONFIG_BOOKE */
870 991
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index f2cf60d38f78..56d8e5d90c5b 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -93,6 +93,12 @@ _ENTRY(crit_r10)
93 .space 4 93 .space 4
94_ENTRY(crit_r11) 94_ENTRY(crit_r11)
95 .space 4 95 .space 4
96_ENTRY(crit_srr0)
97 .space 4
98_ENTRY(crit_srr1)
99 .space 4
100_ENTRY(saved_ksp_limit)
101 .space 4
96 102
97/* 103/*
98 * Exception vector entry code. This code runs with address translation 104 * Exception vector entry code. This code runs with address translation
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
index b0874d228eaf..f277fade1932 100644
--- a/arch/powerpc/kernel/head_booke.h
+++ b/arch/powerpc/kernel/head_booke.h
@@ -72,7 +72,7 @@
72#define DEBUG_STACK_BASE dbgirq_ctx 72#define DEBUG_STACK_BASE dbgirq_ctx
73#define DEBUG_SPRG SPRN_SPRG6W 73#define DEBUG_SPRG SPRN_SPRG6W
74 74
75#define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE) 75#define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE)
76 76
77#ifdef CONFIG_SMP 77#ifdef CONFIG_SMP
78#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ 78#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
@@ -376,4 +376,25 @@ label:
376 addi r3,r1,STACK_FRAME_OVERHEAD; \ 376 addi r3,r1,STACK_FRAME_OVERHEAD; \
377 EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) 377 EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
378 378
379#ifndef __ASSEMBLY__
380struct exception_regs {
381 unsigned long mas0;
382 unsigned long mas1;
383 unsigned long mas2;
384 unsigned long mas3;
385 unsigned long mas6;
386 unsigned long mas7;
387 unsigned long srr0;
388 unsigned long srr1;
389 unsigned long csrr0;
390 unsigned long csrr1;
391 unsigned long dsrr0;
392 unsigned long dsrr1;
393 unsigned long saved_ksp_limit;
394};
395
396/* ensure this structure is always sized to a multiple of the stack alignment */
397#define STACK_EXC_LVL_FRAME_SIZE _ALIGN_UP(sizeof (struct exception_regs), 16)
398
399#endif /* __ASSEMBLY__ */
379#endif /* __HEAD_BOOKE_H__ */ 400#endif /* __HEAD_BOOKE_H__ */