diff options
Diffstat (limited to 'arch/arc/include/asm/entry-arcv2.h')
-rw-r--r-- | arch/arc/include/asm/entry-arcv2.h | 361 |
1 files changed, 190 insertions, 171 deletions
diff --git a/arch/arc/include/asm/entry-arcv2.h b/arch/arc/include/asm/entry-arcv2.h index 225e7df2d8ed..f5ae394ebe06 100644 --- a/arch/arc/include/asm/entry-arcv2.h +++ b/arch/arc/include/asm/entry-arcv2.h | |||
@@ -7,232 +7,251 @@ | |||
7 | #include <asm/irqflags-arcv2.h> | 7 | #include <asm/irqflags-arcv2.h> |
8 | #include <asm/thread_info.h> /* For THREAD_SIZE */ | 8 | #include <asm/thread_info.h> /* For THREAD_SIZE */ |
9 | 9 | ||
10 | /* | ||
11 | * Interrupt/Exception stack layout (pt_regs) for ARCv2 | ||
12 | * (End of struct aligned to end of page [unless nested]) | ||
13 | * | ||
14 | * INTERRUPT EXCEPTION | ||
15 | * | ||
16 | * manual --------------------- manual | ||
17 | * | orig_r0 | | ||
18 | * | event/ECR | | ||
19 | * | bta | | ||
20 | * | user_r25 | | ||
21 | * | gp | | ||
22 | * | fp | | ||
23 | * | sp | | ||
24 | * | r12 | | ||
25 | * | r30 | | ||
26 | * | r58 | | ||
27 | * | r59 | | ||
28 | * hw autosave --------------------- | ||
29 | * optional | r0 | | ||
30 | * | r1 | | ||
31 | * ~ ~ | ||
32 | * | r9 | | ||
33 | * | r10 | | ||
34 | * | r11 | | ||
35 | * | blink | | ||
36 | * | lpe | | ||
37 | * | lps | | ||
38 | * | lpc | | ||
39 | * | ei base | | ||
40 | * | ldi base | | ||
41 | * | jli base | | ||
42 | * --------------------- | ||
43 | * hw autosave | pc / eret | | ||
44 | * mandatory | stat32 / erstatus | | ||
45 | * --------------------- | ||
46 | */ | ||
47 | |||
10 | /*------------------------------------------------------------------------*/ | 48 | /*------------------------------------------------------------------------*/ |
11 | .macro INTERRUPT_PROLOGUE called_from | 49 | .macro INTERRUPT_PROLOGUE |
12 | 50 | ||
13 | ; Before jumping to Interrupt Vector, hardware micro-ops did following: | 51 | ; (A) Before jumping to Interrupt Vector, hardware micro-ops did following: |
14 | ; 1. SP auto-switched to kernel mode stack | 52 | ; 1. SP auto-switched to kernel mode stack |
15 | ; 2. STATUS32.Z flag set to U mode at time of interrupt (U:1, K:0) | 53 | ; 2. STATUS32.Z flag set if in U mode at time of interrupt (U:1,K:0) |
16 | ; 3. Auto saved: r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI, PC, STAT32 | 54 | ; 3. Auto save: (mandatory) Push PC and STAT32 on stack |
55 | ; hardware does even if CONFIG_ARC_IRQ_NO_AUTOSAVE | ||
56 | ; 4. Auto save: (optional) r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI | ||
17 | ; | 57 | ; |
18 | ; Now manually save: r12, sp, fp, gp, r25 | 58 | ; (B) Manually saved some regs: r12,r25,r30, sp,fp,gp, ACCL pair |
19 | 59 | ||
20 | #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE | 60 | #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE |
21 | .ifnc \called_from, exception | 61 | ; carve pt_regs on stack (case #3), PC/STAT32 already on stack |
22 | st.as r9, [sp, -10] ; save r9 in it's final stack slot | 62 | sub sp, sp, SZ_PT_REGS - 8 |
23 | sub sp, sp, 12 ; skip JLI, LDI, EI | ||
24 | |||
25 | PUSH lp_count | ||
26 | PUSHAX lp_start | ||
27 | PUSHAX lp_end | ||
28 | PUSH blink | ||
29 | |||
30 | PUSH r11 | ||
31 | PUSH r10 | ||
32 | |||
33 | sub sp, sp, 4 ; skip r9 | ||
34 | |||
35 | PUSH r8 | ||
36 | PUSH r7 | ||
37 | PUSH r6 | ||
38 | PUSH r5 | ||
39 | PUSH r4 | ||
40 | PUSH r3 | ||
41 | PUSH r2 | ||
42 | PUSH r1 | ||
43 | PUSH r0 | ||
44 | .endif | ||
45 | #endif | ||
46 | 63 | ||
47 | #ifdef CONFIG_ARC_HAS_ACCL_REGS | 64 | __SAVE_REGFILE_HARD |
48 | PUSH r59 | 65 | #else |
49 | PUSH r58 | 66 | ; carve pt_regs on stack (case #4), which grew partially already |
67 | sub sp, sp, PT_r0 | ||
50 | #endif | 68 | #endif |
51 | 69 | ||
52 | PUSH r30 | 70 | __SAVE_REGFILE_SOFT |
53 | PUSH r12 | 71 | .endm |
72 | |||
73 | /*------------------------------------------------------------------------*/ | ||
74 | .macro EXCEPTION_PROLOGUE | ||
75 | |||
76 | ; (A) Before jumping to Exception Vector, hardware micro-ops did following: | ||
77 | ; 1. SP auto-switched to kernel mode stack | ||
78 | ; 2. STATUS32.Z flag set if in U mode at time of exception (U:1,K:0) | ||
79 | ; | ||
80 | ; (B) Manually save the complete reg file below | ||
81 | |||
82 | sub sp, sp, SZ_PT_REGS ; carve pt_regs | ||
83 | |||
84 | ; _HARD saves r10 clobbered by _SOFT as scratch hence comes first | ||
85 | |||
86 | __SAVE_REGFILE_HARD | ||
87 | __SAVE_REGFILE_SOFT | ||
88 | |||
89 | st r0, [sp] ; orig_r0 | ||
90 | |||
91 | lr r10, [eret] | ||
92 | lr r11, [erstatus] | ||
93 | ST2 r10, r11, PT_ret | ||
94 | |||
95 | lr r10, [ecr] | ||
96 | lr r11, [erbta] | ||
97 | ST2 r10, r11, PT_event | ||
98 | |||
99 | ; OUTPUT: r10 has ECR expected by EV_Trap | ||
100 | .endm | ||
101 | |||
102 | /*------------------------------------------------------------------------ | ||
103 | * This macro saves the registers manually which would normally be autosaved | ||
104 | * by hardware on taken interrupts. It is used by | ||
105 | * - exception handlers (which don't have autosave) | ||
106 | * - interrupt autosave disabled due to CONFIG_ARC_IRQ_NO_AUTOSAVE | ||
107 | */ | ||
108 | .macro __SAVE_REGFILE_HARD | ||
109 | |||
110 | ST2 r0, r1, PT_r0 | ||
111 | ST2 r2, r3, PT_r2 | ||
112 | ST2 r4, r5, PT_r4 | ||
113 | ST2 r6, r7, PT_r6 | ||
114 | ST2 r8, r9, PT_r8 | ||
115 | ST2 r10, r11, PT_r10 | ||
116 | |||
117 | st blink, [sp, PT_blink] | ||
118 | |||
119 | lr r10, [lp_end] | ||
120 | lr r11, [lp_start] | ||
121 | ST2 r10, r11, PT_lpe | ||
122 | |||
123 | st lp_count, [sp, PT_lpc] | ||
124 | |||
125 | ; skip JLI, LDI, EI for now | ||
126 | .endm | ||
127 | |||
128 | /*------------------------------------------------------------------------ | ||
129 | * This macros saves a bunch of other registers which can't be autosaved for | ||
130 | * various reasons: | ||
131 | * - r12: the last caller saved scratch reg since hardware saves in pairs so r0-r11 | ||
132 | * - r30: free reg, used by gcc as scratch | ||
133 | * - ACCL/ACCH pair when they exist | ||
134 | */ | ||
135 | .macro __SAVE_REGFILE_SOFT | ||
136 | |||
137 | ST2 gp, fp, PT_r26 ; gp (r26), fp (r27) | ||
138 | |||
139 | st r12, [sp, PT_sp + 4] | ||
140 | st r30, [sp, PT_sp + 8] | ||
54 | 141 | ||
55 | ; Saving pt_regs->sp correctly requires some extra work due to the way | 142 | ; Saving pt_regs->sp correctly requires some extra work due to the way |
56 | ; Auto stack switch works | 143 | ; Auto stack switch works |
57 | ; - U mode: retrieve it from AUX_USER_SP | 144 | ; - U mode: retrieve it from AUX_USER_SP |
58 | ; - K mode: add the offset from current SP where H/w starts auto push | 145 | ; - K mode: add the offset from current SP where H/w starts auto push |
59 | ; | 146 | ; |
60 | ; Utilize the fact that Z bit is set if Intr taken in U mode | 147 | ; 1. Utilize the fact that Z bit is set if Intr taken in U mode |
61 | mov.nz r9, sp | 148 | ; 2. Upon entry SP is always saved (for any inspection, unwinding etc), |
62 | add.nz r9, r9, SZ_PT_REGS - PT_sp - 4 | 149 | ; but on return, restored only if U mode |
63 | bnz 1f | ||
64 | 150 | ||
65 | lr r9, [AUX_USER_SP] | 151 | lr r10, [AUX_USER_SP] ; U mode SP |
66 | 1: | 152 | |
67 | PUSH r9 ; SP | 153 | ; ISA requires ADD.nz to have same dest and src reg operands |
154 | mov.nz r10, sp | ||
155 | add.nz r10, r10, SZ_PT_REGS ; K mode SP | ||
68 | 156 | ||
69 | PUSH fp | 157 | st r10, [sp, PT_sp] ; SP (pt_regs->sp) |
70 | PUSH gp | ||
71 | 158 | ||
72 | #ifdef CONFIG_ARC_CURR_IN_REG | 159 | #ifdef CONFIG_ARC_CURR_IN_REG |
73 | PUSH r25 ; user_r25 | 160 | st r25, [sp, PT_user_r25] |
74 | GET_CURR_TASK_ON_CPU r25 | 161 | GET_CURR_TASK_ON_CPU r25 |
75 | #else | ||
76 | sub sp, sp, 4 | ||
77 | #endif | 162 | #endif |
78 | 163 | ||
79 | .ifnc \called_from, exception | 164 | #ifdef CONFIG_ARC_HAS_ACCL_REGS |
80 | sub sp, sp, 12 ; BTA/ECR/orig_r0 placeholder per pt_regs | 165 | ST2 r58, r59, PT_sp + 12 |
81 | .endif | 166 | #endif |
82 | 167 | ||
83 | .endm | 168 | .endm |
84 | 169 | ||
85 | /*------------------------------------------------------------------------*/ | 170 | /*------------------------------------------------------------------------*/ |
86 | .macro INTERRUPT_EPILOGUE called_from | 171 | .macro __RESTORE_REGFILE_SOFT |
87 | 172 | ||
88 | .ifnc \called_from, exception | 173 | LD2 gp, fp, PT_r26 ; gp (r26), fp (r27) |
89 | add sp, sp, 12 ; skip BTA/ECR/orig_r0 placeholderss | ||
90 | .endif | ||
91 | 174 | ||
92 | #ifdef CONFIG_ARC_CURR_IN_REG | 175 | ld r12, [sp, PT_sp + 4] |
93 | POP r25 | 176 | ld r30, [sp, PT_sp + 8] |
94 | #else | ||
95 | add sp, sp, 4 | ||
96 | #endif | ||
97 | 177 | ||
98 | POP gp | 178 | ; Restore SP (into AUX_USER_SP) only if returning to U mode |
99 | POP fp | 179 | ; - for K mode, it will be implicitly restored as stack is unwound |
100 | 180 | ; - Z flag set on K is inverse of what hardware does on interrupt entry | |
101 | ; Don't touch AUX_USER_SP if returning to K mode (Z bit set) | 181 | ; but that doesn't really matter |
102 | ; (Z bit set on K mode is inverse of INTERRUPT_PROLOGUE) | ||
103 | add.z sp, sp, 4 | ||
104 | bz 1f | 182 | bz 1f |
105 | 183 | ||
106 | POPAX AUX_USER_SP | 184 | ld r10, [sp, PT_sp] ; SP (pt_regs->sp) |
185 | sr r10, [AUX_USER_SP] | ||
107 | 1: | 186 | 1: |
108 | POP r12 | ||
109 | POP r30 | ||
110 | 187 | ||
111 | #ifdef CONFIG_ARC_HAS_ACCL_REGS | 188 | #ifdef CONFIG_ARC_CURR_IN_REG |
112 | POP r58 | 189 | ld r25, [sp, PT_user_r25] |
113 | POP r59 | ||
114 | #endif | 190 | #endif |
115 | 191 | ||
116 | #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE | 192 | #ifdef CONFIG_ARC_HAS_ACCL_REGS |
117 | .ifnc \called_from, exception | 193 | LD2 r58, r59, PT_sp + 12 |
118 | POP r0 | ||
119 | POP r1 | ||
120 | POP r2 | ||
121 | POP r3 | ||
122 | POP r4 | ||
123 | POP r5 | ||
124 | POP r6 | ||
125 | POP r7 | ||
126 | POP r8 | ||
127 | POP r9 | ||
128 | POP r10 | ||
129 | POP r11 | ||
130 | |||
131 | POP blink | ||
132 | POPAX lp_end | ||
133 | POPAX lp_start | ||
134 | |||
135 | POP r9 | ||
136 | mov lp_count, r9 | ||
137 | |||
138 | add sp, sp, 12 ; skip JLI, LDI, EI | ||
139 | ld.as r9, [sp, -10] ; reload r9 which got clobbered | ||
140 | .endif | ||
141 | #endif | 194 | #endif |
195 | .endm | ||
142 | 196 | ||
197 | /*------------------------------------------------------------------------*/ | ||
198 | .macro __RESTORE_REGFILE_HARD | ||
199 | |||
200 | ld blink, [sp, PT_blink] | ||
201 | |||
202 | LD2 r10, r11, PT_lpe | ||
203 | sr r10, [lp_end] | ||
204 | sr r11, [lp_start] | ||
205 | |||
206 | ld r10, [sp, PT_lpc] ; lp_count can't be target of LD | ||
207 | mov lp_count, r10 | ||
208 | |||
209 | LD2 r0, r1, PT_r0 | ||
210 | LD2 r2, r3, PT_r2 | ||
211 | LD2 r4, r5, PT_r4 | ||
212 | LD2 r6, r7, PT_r6 | ||
213 | LD2 r8, r9, PT_r8 | ||
214 | LD2 r10, r11, PT_r10 | ||
143 | .endm | 215 | .endm |
144 | 216 | ||
217 | |||
145 | /*------------------------------------------------------------------------*/ | 218 | /*------------------------------------------------------------------------*/ |
146 | .macro EXCEPTION_PROLOGUE | 219 | .macro INTERRUPT_EPILOGUE |
147 | 220 | ||
148 | ; Before jumping to Exception Vector, hardware micro-ops did following: | 221 | ; INPUT: r0 has STAT32 of calling context |
149 | ; 1. SP auto-switched to kernel mode stack | 222 | ; INPUT: Z flag set if returning to K mode |
150 | ; 2. STATUS32.Z flag set to U mode at time of interrupt (U:1,K:0) | ||
151 | ; | ||
152 | ; Now manually save the complete reg file | ||
153 | |||
154 | PUSH r9 ; freeup a register: slot of erstatus | ||
155 | |||
156 | PUSHAX eret | ||
157 | sub sp, sp, 12 ; skip JLI, LDI, EI | ||
158 | PUSH lp_count | ||
159 | PUSHAX lp_start | ||
160 | PUSHAX lp_end | ||
161 | PUSH blink | ||
162 | |||
163 | PUSH r11 | ||
164 | PUSH r10 | ||
165 | |||
166 | ld.as r9, [sp, 10] ; load stashed r9 (status32 stack slot) | ||
167 | lr r10, [erstatus] | ||
168 | st.as r10, [sp, 10] ; save status32 at it's right stack slot | ||
169 | |||
170 | PUSH r9 | ||
171 | PUSH r8 | ||
172 | PUSH r7 | ||
173 | PUSH r6 | ||
174 | PUSH r5 | ||
175 | PUSH r4 | ||
176 | PUSH r3 | ||
177 | PUSH r2 | ||
178 | PUSH r1 | ||
179 | PUSH r0 | ||
180 | |||
181 | ; -- for interrupts, regs above are auto-saved by h/w in that order -- | ||
182 | ; Now do what ISR prologue does (manually save r12, sp, fp, gp, r25) | ||
183 | ; | ||
184 | ; Set Z flag if this was from U mode (expected by INTERRUPT_PROLOGUE) | ||
185 | ; Although H/w exception micro-ops do set Z flag for U mode (just like | ||
186 | ; for interrupts), it could get clobbered in case we soft land here from | ||
187 | ; a TLB Miss exception handler (tlbex.S) | ||
188 | 223 | ||
189 | and r10, r10, STATUS_U_MASK | 224 | ; _SOFT clobbers r10 restored by _HARD hence the order |
190 | xor.f 0, r10, STATUS_U_MASK | ||
191 | 225 | ||
192 | INTERRUPT_PROLOGUE exception | 226 | __RESTORE_REGFILE_SOFT |
193 | 227 | ||
194 | PUSHAX erbta | 228 | #ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE |
195 | PUSHAX ecr ; r9 contains ECR, expected by EV_Trap | 229 | __RESTORE_REGFILE_HARD |
230 | add sp, sp, SZ_PT_REGS - 8 | ||
231 | #else | ||
232 | add sp, sp, PT_r0 | ||
233 | #endif | ||
196 | 234 | ||
197 | PUSH r0 ; orig_r0 | ||
198 | .endm | 235 | .endm |
199 | 236 | ||
200 | /*------------------------------------------------------------------------*/ | 237 | /*------------------------------------------------------------------------*/ |
201 | .macro EXCEPTION_EPILOGUE | 238 | .macro EXCEPTION_EPILOGUE |
202 | 239 | ||
203 | ; Assumes r0 has PT_status32 | 240 | ; INPUT: r0 has STAT32 of calling context |
204 | btst r0, STATUS_U_BIT ; Z flag set if K, used in INTERRUPT_EPILOGUE | ||
205 | |||
206 | add sp, sp, 8 ; orig_r0/ECR don't need restoring | ||
207 | POPAX erbta | ||
208 | |||
209 | INTERRUPT_EPILOGUE exception | ||
210 | 241 | ||
211 | POP r0 | 242 | btst r0, STATUS_U_BIT ; Z flag set if K, used in restoring SP |
212 | POP r1 | ||
213 | POP r2 | ||
214 | POP r3 | ||
215 | POP r4 | ||
216 | POP r5 | ||
217 | POP r6 | ||
218 | POP r7 | ||
219 | POP r8 | ||
220 | POP r9 | ||
221 | POP r10 | ||
222 | POP r11 | ||
223 | 243 | ||
224 | POP blink | 244 | ld r10, [sp, PT_event + 4] |
225 | POPAX lp_end | 245 | sr r10, [erbta] |
226 | POPAX lp_start | ||
227 | 246 | ||
228 | POP r9 | 247 | LD2 r10, r11, PT_ret |
229 | mov lp_count, r9 | 248 | sr r10, [eret] |
249 | sr r11, [erstatus] | ||
230 | 250 | ||
231 | add sp, sp, 12 ; skip JLI, LDI, EI | 251 | __RESTORE_REGFILE_SOFT |
232 | POPAX eret | 252 | __RESTORE_REGFILE_HARD |
233 | POPAX erstatus | ||
234 | 253 | ||
235 | ld.as r9, [sp, -12] ; reload r9 which got clobbered | 254 | add sp, sp, SZ_PT_REGS |
236 | .endm | 255 | .endm |
237 | 256 | ||
238 | .macro FAKE_RET_FROM_EXCPN | 257 | .macro FAKE_RET_FROM_EXCPN |