diff options
author | Kumar Gala <galak@freescale.com> | 2005-06-21 20:15:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-21 21:46:25 -0400 |
commit | 1492ec8069ea6f82bc32df27cabbec72e554e2b8 (patch) | |
tree | 09e52d150482a105a63dc4b71758a7aa99ecb28c /arch | |
parent | 5be061eee931db2718feecaf10df17610386202b (diff) |
[PATCH] ppc32: Factor out common exception code into macro's for 4xx/Book-E
4xx and Book-E PPC's have several exception levels. The code to handle
each level is fairly regular. Turning the code into macro's will ease the
handling of future exception levels (debug) in forth coming chips.
Signed-off-by: Kumar Gala <kumar.gala@freescale.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ppc/kernel/entry.S | 164 | ||||
-rw-r--r-- | arch/ppc/kernel/head_booke.h | 94 |
2 files changed, 87 insertions, 171 deletions
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 661523707e8c..8377b6ca26da 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S | |||
@@ -46,26 +46,23 @@ | |||
46 | 46 | ||
47 | #ifdef CONFIG_BOOKE | 47 | #ifdef CONFIG_BOOKE |
48 | #include "head_booke.h" | 48 | #include "head_booke.h" |
49 | #define TRANSFER_TO_HANDLER_EXC_LEVEL(exc_level) \ | ||
50 | mtspr exc_level##_SPRG,r8; \ | ||
51 | BOOKE_LOAD_EXC_LEVEL_STACK(exc_level); \ | ||
52 | lwz r0,GPR10-INT_FRAME_SIZE(r8); \ | ||
53 | stw r0,GPR10(r11); \ | ||
54 | lwz r0,GPR11-INT_FRAME_SIZE(r8); \ | ||
55 | stw r0,GPR11(r11); \ | ||
56 | mfspr r8,exc_level##_SPRG | ||
57 | |||
49 | .globl mcheck_transfer_to_handler | 58 | .globl mcheck_transfer_to_handler |
50 | mcheck_transfer_to_handler: | 59 | mcheck_transfer_to_handler: |
51 | mtspr MCHECK_SPRG,r8 | 60 | TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK) |
52 | BOOKE_LOAD_MCHECK_STACK | ||
53 | lwz r0,GPR10-INT_FRAME_SIZE(r8) | ||
54 | stw r0,GPR10(r11) | ||
55 | lwz r0,GPR11-INT_FRAME_SIZE(r8) | ||
56 | stw r0,GPR11(r11) | ||
57 | mfspr r8,MCHECK_SPRG | ||
58 | b transfer_to_handler_full | 61 | b transfer_to_handler_full |
59 | 62 | ||
60 | .globl crit_transfer_to_handler | 63 | .globl crit_transfer_to_handler |
61 | crit_transfer_to_handler: | 64 | crit_transfer_to_handler: |
62 | mtspr CRIT_SPRG,r8 | 65 | TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT) |
63 | BOOKE_LOAD_CRIT_STACK | ||
64 | lwz r0,GPR10-INT_FRAME_SIZE(r8) | ||
65 | stw r0,GPR10(r11) | ||
66 | lwz r0,GPR11-INT_FRAME_SIZE(r8) | ||
67 | stw r0,GPR11(r11) | ||
68 | mfspr r8,CRIT_SPRG | ||
69 | /* fall through */ | 66 | /* fall through */ |
70 | #endif | 67 | #endif |
71 | 68 | ||
@@ -783,99 +780,64 @@ exc_exit_restart_end: | |||
783 | * time of the critical interrupt. | 780 | * time of the critical interrupt. |
784 | * | 781 | * |
785 | */ | 782 | */ |
786 | .globl ret_from_crit_exc | ||
787 | ret_from_crit_exc: | ||
788 | REST_NVGPRS(r1) | ||
789 | lwz r3,_MSR(r1) | ||
790 | andi. r3,r3,MSR_PR | ||
791 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) | ||
792 | bne user_exc_return | ||
793 | |||
794 | lwz r0,GPR0(r1) | ||
795 | lwz r2,GPR2(r1) | ||
796 | REST_4GPRS(3, r1) | ||
797 | REST_2GPRS(7, r1) | ||
798 | |||
799 | lwz r10,_XER(r1) | ||
800 | lwz r11,_CTR(r1) | ||
801 | mtspr SPRN_XER,r10 | ||
802 | mtctr r11 | ||
803 | |||
804 | PPC405_ERR77(0,r1) | ||
805 | stwcx. r0,0,r1 /* to clear the reservation */ | ||
806 | |||
807 | lwz r11,_LINK(r1) | ||
808 | mtlr r11 | ||
809 | lwz r10,_CCR(r1) | ||
810 | mtcrf 0xff,r10 | ||
811 | #ifdef CONFIG_40x | 783 | #ifdef CONFIG_40x |
812 | /* avoid any possible TLB misses here by turning off MSR.DR, we | 784 | #define PPC_40x_TURN_OFF_MSR_DR \ |
813 | * assume the instructions here are mapped by a pinned TLB entry */ | 785 | /* avoid any possible TLB misses here by turning off MSR.DR, we \ |
814 | li r10,MSR_IR | 786 | * assume the instructions here are mapped by a pinned TLB entry */ \ |
815 | mtmsr r10 | 787 | li r10,MSR_IR; \ |
816 | isync | 788 | mtmsr r10; \ |
817 | tophys(r1, r1) | 789 | isync; \ |
790 | tophys(r1, r1); | ||
791 | #else | ||
792 | #define PPC_40x_TURN_OFF_MSR_DR | ||
818 | #endif | 793 | #endif |
819 | lwz r9,_DEAR(r1) | 794 | |
820 | lwz r10,_ESR(r1) | 795 | #define RET_FROM_EXC_LEVEL(exc_lvl_srr0, exc_lvl_srr1, exc_lvl_rfi) \ |
821 | mtspr SPRN_DEAR,r9 | 796 | REST_NVGPRS(r1); \ |
822 | mtspr SPRN_ESR,r10 | 797 | lwz r3,_MSR(r1); \ |
823 | lwz r11,_NIP(r1) | 798 | andi. r3,r3,MSR_PR; \ |
824 | lwz r12,_MSR(r1) | 799 | LOAD_MSR_KERNEL(r10,MSR_KERNEL); \ |
825 | mtspr SPRN_CSRR0,r11 | 800 | bne user_exc_return; \ |
826 | mtspr SPRN_CSRR1,r12 | 801 | lwz r0,GPR0(r1); \ |
827 | lwz r9,GPR9(r1) | 802 | lwz r2,GPR2(r1); \ |
828 | lwz r12,GPR12(r1) | 803 | REST_4GPRS(3, r1); \ |
829 | lwz r10,GPR10(r1) | 804 | REST_2GPRS(7, r1); \ |
830 | lwz r11,GPR11(r1) | 805 | lwz r10,_XER(r1); \ |
831 | lwz r1,GPR1(r1) | 806 | lwz r11,_CTR(r1); \ |
832 | PPC405_ERR77_SYNC | 807 | mtspr SPRN_XER,r10; \ |
833 | rfci | 808 | mtctr r11; \ |
834 | b . /* prevent prefetch past rfci */ | 809 | PPC405_ERR77(0,r1); \ |
810 | stwcx. r0,0,r1; /* to clear the reservation */ \ | ||
811 | lwz r11,_LINK(r1); \ | ||
812 | mtlr r11; \ | ||
813 | lwz r10,_CCR(r1); \ | ||
814 | mtcrf 0xff,r10; \ | ||
815 | PPC_40x_TURN_OFF_MSR_DR; \ | ||
816 | lwz r9,_DEAR(r1); \ | ||
817 | lwz r10,_ESR(r1); \ | ||
818 | mtspr SPRN_DEAR,r9; \ | ||
819 | mtspr SPRN_ESR,r10; \ | ||
820 | lwz r11,_NIP(r1); \ | ||
821 | lwz r12,_MSR(r1); \ | ||
822 | mtspr exc_lvl_srr0,r11; \ | ||
823 | mtspr exc_lvl_srr1,r12; \ | ||
824 | lwz r9,GPR9(r1); \ | ||
825 | lwz r12,GPR12(r1); \ | ||
826 | lwz r10,GPR10(r1); \ | ||
827 | lwz r11,GPR11(r1); \ | ||
828 | lwz r1,GPR1(r1); \ | ||
829 | PPC405_ERR77_SYNC; \ | ||
830 | exc_lvl_rfi; \ | ||
831 | b .; /* prevent prefetch past exc_lvl_rfi */ | ||
832 | |||
833 | .globl ret_from_crit_exc | ||
834 | ret_from_crit_exc: | ||
835 | RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) | ||
835 | 836 | ||
836 | #ifdef CONFIG_BOOKE | 837 | #ifdef CONFIG_BOOKE |
837 | /* | ||
838 | * Return from a machine check interrupt, similar to a critical | ||
839 | * interrupt. | ||
840 | */ | ||
841 | .globl ret_from_mcheck_exc | 838 | .globl ret_from_mcheck_exc |
842 | ret_from_mcheck_exc: | 839 | ret_from_mcheck_exc: |
843 | REST_NVGPRS(r1) | 840 | RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) |
844 | lwz r3,_MSR(r1) | ||
845 | andi. r3,r3,MSR_PR | ||
846 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) | ||
847 | bne user_exc_return | ||
848 | |||
849 | lwz r0,GPR0(r1) | ||
850 | lwz r2,GPR2(r1) | ||
851 | REST_4GPRS(3, r1) | ||
852 | REST_2GPRS(7, r1) | ||
853 | |||
854 | lwz r10,_XER(r1) | ||
855 | lwz r11,_CTR(r1) | ||
856 | mtspr SPRN_XER,r10 | ||
857 | mtctr r11 | ||
858 | |||
859 | stwcx. r0,0,r1 /* to clear the reservation */ | ||
860 | |||
861 | lwz r11,_LINK(r1) | ||
862 | mtlr r11 | ||
863 | lwz r10,_CCR(r1) | ||
864 | mtcrf 0xff,r10 | ||
865 | lwz r9,_DEAR(r1) | ||
866 | lwz r10,_ESR(r1) | ||
867 | mtspr SPRN_DEAR,r9 | ||
868 | mtspr SPRN_ESR,r10 | ||
869 | lwz r11,_NIP(r1) | ||
870 | lwz r12,_MSR(r1) | ||
871 | mtspr SPRN_MCSRR0,r11 | ||
872 | mtspr SPRN_MCSRR1,r12 | ||
873 | lwz r9,GPR9(r1) | ||
874 | lwz r12,GPR12(r1) | ||
875 | lwz r10,GPR10(r1) | ||
876 | lwz r11,GPR11(r1) | ||
877 | lwz r1,GPR1(r1) | ||
878 | RFMCI | ||
879 | #endif /* CONFIG_BOOKE */ | 841 | #endif /* CONFIG_BOOKE */ |
880 | 842 | ||
881 | /* | 843 | /* |
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h index f213d12eec08..9c50f9d2657c 100644 --- a/arch/ppc/kernel/head_booke.h +++ b/arch/ppc/kernel/head_booke.h | |||
@@ -67,46 +67,36 @@ | |||
67 | #define CRIT_STACK_TOP (exception_stack_top) | 67 | #define CRIT_STACK_TOP (exception_stack_top) |
68 | 68 | ||
69 | #ifdef CONFIG_SMP | 69 | #ifdef CONFIG_SMP |
70 | #define BOOKE_LOAD_CRIT_STACK \ | 70 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ |
71 | mfspr r8,SPRN_PIR; \ | 71 | mfspr r8,SPRN_PIR; \ |
72 | mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ | 72 | mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ |
73 | neg r8,r8; \ | 73 | neg r8,r8; \ |
74 | addis r8,r8,CRIT_STACK_TOP@ha; \ | 74 | addis r8,r8,level##_STACK_TOP@ha; \ |
75 | addi r8,r8,CRIT_STACK_TOP@l | 75 | addi r8,r8,level##_STACK_TOP@l |
76 | #define BOOKE_LOAD_MCHECK_STACK \ | ||
77 | mfspr r8,SPRN_PIR; \ | ||
78 | mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ | ||
79 | neg r8,r8; \ | ||
80 | addis r8,r8,MCHECK_STACK_TOP@ha; \ | ||
81 | addi r8,r8,MCHECK_STACK_TOP@l | ||
82 | #else | 76 | #else |
83 | #define BOOKE_LOAD_CRIT_STACK \ | 77 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ |
84 | lis r8,CRIT_STACK_TOP@h; \ | 78 | lis r8,level##_STACK_TOP@h; \ |
85 | ori r8,r8,CRIT_STACK_TOP@l | 79 | ori r8,r8,level##_STACK_TOP@l |
86 | #define BOOKE_LOAD_MCHECK_STACK \ | ||
87 | lis r8,MCHECK_STACK_TOP@h; \ | ||
88 | ori r8,r8,MCHECK_STACK_TOP@l | ||
89 | #endif | 80 | #endif |
90 | 81 | ||
91 | /* | 82 | /* |
92 | * Exception prolog for critical exceptions. This is a little different | 83 | * Exception prolog for critical/machine check exceptions. This is a |
93 | * from the normal exception prolog above since a critical exception | 84 | * little different from the normal exception prolog above since a |
94 | * can potentially occur at any point during normal exception processing. | 85 | * critical/machine check exception can potentially occur at any point |
95 | * Thus we cannot use the same SPRG registers as the normal prolog above. | 86 | * during normal exception processing. Thus we cannot use the same SPRG |
96 | * Instead we use a portion of the critical exception stack at low physical | 87 | * registers as the normal prolog above. Instead we use a portion of the |
97 | * addresses. | 88 | * critical/machine check exception stack at low physical addresses. |
98 | */ | 89 | */ |
99 | 90 | #define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \ | |
100 | #define CRITICAL_EXCEPTION_PROLOG \ | 91 | mtspr exc_level##_SPRG,r8; \ |
101 | mtspr CRIT_SPRG,r8; \ | 92 | BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \ |
102 | BOOKE_LOAD_CRIT_STACK; /* r8 points to the crit stack */ \ | ||
103 | stw r10,GPR10-INT_FRAME_SIZE(r8); \ | 93 | stw r10,GPR10-INT_FRAME_SIZE(r8); \ |
104 | stw r11,GPR11-INT_FRAME_SIZE(r8); \ | 94 | stw r11,GPR11-INT_FRAME_SIZE(r8); \ |
105 | mfcr r10; /* save CR in r10 for now */\ | 95 | mfcr r10; /* save CR in r10 for now */\ |
106 | mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ | 96 | mfspr r11,exc_level_srr1; /* check whether user or kernel */\ |
107 | andi. r11,r11,MSR_PR; \ | 97 | andi. r11,r11,MSR_PR; \ |
108 | mr r11,r8; \ | 98 | mr r11,r8; \ |
109 | mfspr r8,CRIT_SPRG; \ | 99 | mfspr r8,exc_level##_SPRG; \ |
110 | beq 1f; \ | 100 | beq 1f; \ |
111 | /* COMING FROM USER MODE */ \ | 101 | /* COMING FROM USER MODE */ \ |
112 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ | 102 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ |
@@ -122,9 +112,9 @@ | |||
122 | stw r12,_DEAR(r11); /* since they may have had stuff */\ | 112 | stw r12,_DEAR(r11); /* since they may have had stuff */\ |
123 | mfspr r9,SPRN_ESR; /* in them at the point where the */\ | 113 | mfspr r9,SPRN_ESR; /* in them at the point where the */\ |
124 | stw r9,_ESR(r11); /* exception was taken */\ | 114 | stw r9,_ESR(r11); /* exception was taken */\ |
125 | mfspr r12,SPRN_CSRR0; \ | 115 | mfspr r12,exc_level_srr0; \ |
126 | stw r1,GPR1(r11); \ | 116 | stw r1,GPR1(r11); \ |
127 | mfspr r9,SPRN_CSRR1; \ | 117 | mfspr r9,exc_level_srr1; \ |
128 | stw r1,0(r11); \ | 118 | stw r1,0(r11); \ |
129 | mr r1,r11; \ | 119 | mr r1,r11; \ |
130 | rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ | 120 | rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ |
@@ -132,45 +122,10 @@ | |||
132 | SAVE_4GPRS(3, r11); \ | 122 | SAVE_4GPRS(3, r11); \ |
133 | SAVE_2GPRS(7, r11) | 123 | SAVE_2GPRS(7, r11) |
134 | 124 | ||
135 | /* | 125 | #define CRITICAL_EXCEPTION_PROLOG \ |
136 | * Exception prolog for machine check exceptions. This is similar to | 126 | EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1) |
137 | * the critical exception prolog, except that machine check exceptions | 127 | #define MCHECK_EXCEPTION_PROLOG \ |
138 | * have their stack. | 128 | EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1) |
139 | */ | ||
140 | #define MCHECK_EXCEPTION_PROLOG \ | ||
141 | mtspr MCHECK_SPRG,r8; \ | ||
142 | BOOKE_LOAD_MCHECK_STACK; /* r8 points to the mcheck stack */\ | ||
143 | stw r10,GPR10-INT_FRAME_SIZE(r8); \ | ||
144 | stw r11,GPR11-INT_FRAME_SIZE(r8); \ | ||
145 | mfcr r10; /* save CR in r10 for now */\ | ||
146 | mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ | ||
147 | andi. r11,r11,MSR_PR; \ | ||
148 | mr r11,r8; \ | ||
149 | mfspr r8,MCHECK_SPRG; \ | ||
150 | beq 1f; \ | ||
151 | /* COMING FROM USER MODE */ \ | ||
152 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ | ||
153 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ | ||
154 | addi r11,r11,THREAD_SIZE; \ | ||
155 | 1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ | ||
156 | stw r10,_CCR(r11); /* save various registers */\ | ||
157 | stw r12,GPR12(r11); \ | ||
158 | stw r9,GPR9(r11); \ | ||
159 | mflr r10; \ | ||
160 | stw r10,_LINK(r11); \ | ||
161 | mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ | ||
162 | stw r12,_DEAR(r11); /* since they may have had stuff */\ | ||
163 | mfspr r9,SPRN_ESR; /* in them at the point where the */\ | ||
164 | stw r9,_ESR(r11); /* exception was taken */\ | ||
165 | mfspr r12,SPRN_MCSRR0; \ | ||
166 | stw r1,GPR1(r11); \ | ||
167 | mfspr r9,SPRN_MCSRR1; \ | ||
168 | stw r1,0(r11); \ | ||
169 | mr r1,r11; \ | ||
170 | rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ | ||
171 | stw r0,GPR0(r11); \ | ||
172 | SAVE_4GPRS(3, r11); \ | ||
173 | SAVE_2GPRS(7, r11) | ||
174 | 129 | ||
175 | /* | 130 | /* |
176 | * Exception vectors. | 131 | * Exception vectors. |
@@ -237,7 +192,6 @@ label: | |||
237 | EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ | 192 | EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ |
238 | ret_from_except) | 193 | ret_from_except) |
239 | 194 | ||
240 | |||
241 | /* Check for a single step debug exception while in an exception | 195 | /* Check for a single step debug exception while in an exception |
242 | * handler before state has been saved. This is to catch the case | 196 | * handler before state has been saved. This is to catch the case |
243 | * where an instruction that we are trying to single step causes | 197 | * where an instruction that we are trying to single step causes |
@@ -291,7 +245,7 @@ label: | |||
291 | lwz r9,GPR9(r11); \ | 245 | lwz r9,GPR9(r11); \ |
292 | lwz r12,GPR12(r11); \ | 246 | lwz r12,GPR12(r11); \ |
293 | mtspr CRIT_SPRG,r8; \ | 247 | mtspr CRIT_SPRG,r8; \ |
294 | BOOKE_LOAD_CRIT_STACK; /* r8 points to the crit stack */ \ | 248 | BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \ |
295 | lwz r10,GPR10-INT_FRAME_SIZE(r8); \ | 249 | lwz r10,GPR10-INT_FRAME_SIZE(r8); \ |
296 | lwz r11,GPR11-INT_FRAME_SIZE(r8); \ | 250 | lwz r11,GPR11-INT_FRAME_SIZE(r8); \ |
297 | mfspr r8,CRIT_SPRG; \ | 251 | mfspr r8,CRIT_SPRG; \ |