diff options
Diffstat (limited to 'arch/sparc/kernel/rtrap.S')
-rw-r--r-- | arch/sparc/kernel/rtrap.S | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S new file mode 100644 index 000000000000..f7460d897e79 --- /dev/null +++ b/arch/sparc/kernel/rtrap.S | |||
@@ -0,0 +1,319 @@ | |||
1 | /* $Id: rtrap.S,v 1.58 2002/01/31 03:30:05 davem Exp $ | ||
2 | * rtrap.S: Return from Sparc trap low-level code. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
6 | |||
7 | #include <asm/page.h> | ||
8 | #include <asm/ptrace.h> | ||
9 | #include <asm/psr.h> | ||
10 | #include <asm/asi.h> | ||
11 | #include <asm/smp.h> | ||
12 | #include <asm/contregs.h> | ||
13 | #include <asm/winmacro.h> | ||
14 | #include <asm/asmmacro.h> | ||
15 | #include <asm/thread_info.h> | ||
16 | |||
17 | #define t_psr l0 | ||
18 | #define t_pc l1 | ||
19 | #define t_npc l2 | ||
20 | #define t_wim l3 | ||
21 | #define twin_tmp1 l4 | ||
22 | #define glob_tmp g4 | ||
23 | #define curptr g6 | ||
24 | |||
25 | /* 7 WINDOW SPARC PATCH INSTRUCTIONS */ | ||
26 | .globl rtrap_7win_patch1, rtrap_7win_patch2, rtrap_7win_patch3 | ||
27 | .globl rtrap_7win_patch4, rtrap_7win_patch5 | ||
28 | rtrap_7win_patch1: srl %t_wim, 0x6, %glob_tmp | ||
29 | rtrap_7win_patch2: and %glob_tmp, 0x7f, %glob_tmp | ||
30 | rtrap_7win_patch3: srl %g1, 7, %g2 | ||
31 | rtrap_7win_patch4: srl %g2, 6, %g2 | ||
32 | rtrap_7win_patch5: and %g1, 0x7f, %g1 | ||
33 | /* END OF PATCH INSTRUCTIONS */ | ||
34 | |||
35 | /* We need to check for a few things which are: | ||
36 | * 1) The need to call schedule() because this | ||
37 | * processes quantum is up. | ||
38 | * 2) Pending signals for this process, if any | ||
39 | * exist we need to call do_signal() to do | ||
40 | * the needy. | ||
41 | * | ||
42 | * Else we just check if the rett would land us | ||
43 | * in an invalid window, if so we need to grab | ||
44 | * it off the user/kernel stack first. | ||
45 | */ | ||
46 | |||
47 | .globl ret_trap_entry, rtrap_patch1, rtrap_patch2 | ||
48 | .globl rtrap_patch3, rtrap_patch4, rtrap_patch5 | ||
49 | .globl ret_trap_lockless_ipi | ||
50 | ret_trap_entry: | ||
51 | ret_trap_lockless_ipi: | ||
52 | andcc %t_psr, PSR_PS, %g0 | ||
53 | be 1f | ||
54 | nop | ||
55 | |||
56 | wr %t_psr, 0x0, %psr | ||
57 | b ret_trap_kernel | ||
58 | nop | ||
59 | |||
60 | 1: | ||
61 | ld [%curptr + TI_FLAGS], %g2 | ||
62 | andcc %g2, (_TIF_NEED_RESCHED), %g0 | ||
63 | be signal_p | ||
64 | nop | ||
65 | |||
66 | call schedule | ||
67 | nop | ||
68 | |||
69 | ld [%curptr + TI_FLAGS], %g2 | ||
70 | signal_p: | ||
71 | andcc %g2, (_TIF_NOTIFY_RESUME|_TIF_SIGPENDING), %g0 | ||
72 | bz,a ret_trap_continue | ||
73 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr | ||
74 | |||
75 | clr %o0 | ||
76 | mov %l5, %o2 | ||
77 | mov %l6, %o3 | ||
78 | call do_signal | ||
79 | add %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr | ||
80 | |||
81 | /* Fall through. */ | ||
82 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr | ||
83 | clr %l6 | ||
84 | ret_trap_continue: | ||
85 | wr %t_psr, 0x0, %psr | ||
86 | WRITE_PAUSE | ||
87 | |||
88 | ld [%curptr + TI_W_SAVED], %twin_tmp1 | ||
89 | orcc %g0, %twin_tmp1, %g0 | ||
90 | be ret_trap_nobufwins | ||
91 | nop | ||
92 | |||
93 | wr %t_psr, PSR_ET, %psr | ||
94 | WRITE_PAUSE | ||
95 | |||
96 | mov 1, %o1 | ||
97 | call try_to_clear_window_buffer | ||
98 | add %sp, STACKFRAME_SZ, %o0 | ||
99 | |||
100 | b signal_p | ||
101 | ld [%curptr + TI_FLAGS], %g2 | ||
102 | |||
103 | ret_trap_nobufwins: | ||
104 | /* Load up the user's out registers so we can pull | ||
105 | * a window from the stack, if necessary. | ||
106 | */ | ||
107 | LOAD_PT_INS(sp) | ||
108 | |||
109 | /* If there are already live user windows in the | ||
110 | * set we can return from trap safely. | ||
111 | */ | ||
112 | ld [%curptr + TI_UWINMASK], %twin_tmp1 | ||
113 | orcc %g0, %twin_tmp1, %g0 | ||
114 | bne ret_trap_userwins_ok | ||
115 | nop | ||
116 | |||
117 | /* Calculate new %wim, we have to pull a register | ||
118 | * window from the users stack. | ||
119 | */ | ||
120 | ret_trap_pull_one_window: | ||
121 | rd %wim, %t_wim | ||
122 | sll %t_wim, 0x1, %twin_tmp1 | ||
123 | rtrap_patch1: srl %t_wim, 0x7, %glob_tmp | ||
124 | or %glob_tmp, %twin_tmp1, %glob_tmp | ||
125 | rtrap_patch2: and %glob_tmp, 0xff, %glob_tmp | ||
126 | |||
127 | wr %glob_tmp, 0x0, %wim | ||
128 | |||
129 | /* Here comes the architecture specific | ||
130 | * branch to the user stack checking routine | ||
131 | * for return from traps. | ||
132 | */ | ||
133 | .globl rtrap_mmu_patchme | ||
134 | rtrap_mmu_patchme: b sun4c_rett_stackchk | ||
135 | andcc %fp, 0x7, %g0 | ||
136 | |||
137 | ret_trap_userwins_ok: | ||
138 | LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) | ||
139 | or %t_pc, %t_npc, %g2 | ||
140 | andcc %g2, 0x3, %g0 | ||
141 | be 1f | ||
142 | nop | ||
143 | |||
144 | b ret_trap_unaligned_pc | ||
145 | add %sp, STACKFRAME_SZ, %o0 | ||
146 | |||
147 | 1: | ||
148 | LOAD_PT_YREG(sp, g1) | ||
149 | LOAD_PT_GLOBALS(sp) | ||
150 | |||
151 | wr %t_psr, 0x0, %psr | ||
152 | WRITE_PAUSE | ||
153 | |||
154 | jmp %t_pc | ||
155 | rett %t_npc | ||
156 | |||
157 | ret_trap_unaligned_pc: | ||
158 | ld [%sp + STACKFRAME_SZ + PT_PC], %o1 | ||
159 | ld [%sp + STACKFRAME_SZ + PT_NPC], %o2 | ||
160 | ld [%sp + STACKFRAME_SZ + PT_PSR], %o3 | ||
161 | |||
162 | wr %t_wim, 0x0, %wim ! or else... | ||
163 | |||
164 | wr %t_psr, PSR_ET, %psr | ||
165 | WRITE_PAUSE | ||
166 | |||
167 | call do_memaccess_unaligned | ||
168 | nop | ||
169 | |||
170 | b signal_p | ||
171 | ld [%curptr + TI_FLAGS], %g2 | ||
172 | |||
173 | ret_trap_kernel: | ||
174 | /* Will the rett land us in the invalid window? */ | ||
175 | mov 2, %g1 | ||
176 | sll %g1, %t_psr, %g1 | ||
177 | rtrap_patch3: srl %g1, 8, %g2 | ||
178 | or %g1, %g2, %g1 | ||
179 | rd %wim, %g2 | ||
180 | andcc %g2, %g1, %g0 | ||
181 | be 1f ! Nope, just return from the trap | ||
182 | sll %g2, 0x1, %g1 | ||
183 | |||
184 | /* We have to grab a window before returning. */ | ||
185 | rtrap_patch4: srl %g2, 7, %g2 | ||
186 | or %g1, %g2, %g1 | ||
187 | rtrap_patch5: and %g1, 0xff, %g1 | ||
188 | |||
189 | wr %g1, 0x0, %wim | ||
190 | |||
191 | /* Grrr, make sure we load from the right %sp... */ | ||
192 | LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) | ||
193 | |||
194 | restore %g0, %g0, %g0 | ||
195 | LOAD_WINDOW(sp) | ||
196 | b 2f | ||
197 | save %g0, %g0, %g0 | ||
198 | |||
199 | /* Reload the entire frame in case this is from a | ||
200 | * kernel system call or whatever... | ||
201 | */ | ||
202 | 1: | ||
203 | LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) | ||
204 | 2: | ||
205 | wr %t_psr, 0x0, %psr | ||
206 | WRITE_PAUSE | ||
207 | |||
208 | jmp %t_pc | ||
209 | rett %t_npc | ||
210 | |||
211 | ret_trap_user_stack_is_bolixed: | ||
212 | wr %t_wim, 0x0, %wim | ||
213 | |||
214 | wr %t_psr, PSR_ET, %psr | ||
215 | WRITE_PAUSE | ||
216 | |||
217 | call window_ret_fault | ||
218 | add %sp, STACKFRAME_SZ, %o0 | ||
219 | |||
220 | b signal_p | ||
221 | ld [%curptr + TI_FLAGS], %g2 | ||
222 | |||
223 | |||
224 | .globl sun4c_rett_stackchk | ||
225 | sun4c_rett_stackchk: | ||
226 | be 1f | ||
227 | and %fp, 0xfff, %g1 ! delay slot | ||
228 | |||
229 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
230 | wr %t_wim, 0x0, %wim | ||
231 | |||
232 | /* See if we have to check the sanity of one page or two */ | ||
233 | 1: | ||
234 | add %g1, 0x38, %g1 | ||
235 | sra %fp, 29, %g2 | ||
236 | add %g2, 0x1, %g2 | ||
237 | andncc %g2, 0x1, %g0 | ||
238 | be 1f | ||
239 | andncc %g1, 0xff8, %g0 | ||
240 | |||
241 | /* %sp is in vma hole, yuck */ | ||
242 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
243 | wr %t_wim, 0x0, %wim | ||
244 | |||
245 | 1: | ||
246 | be sun4c_rett_onepage /* Only one page to check */ | ||
247 | lda [%fp] ASI_PTE, %g2 | ||
248 | |||
249 | sun4c_rett_twopages: | ||
250 | add %fp, 0x38, %g1 | ||
251 | sra %g1, 29, %g2 | ||
252 | add %g2, 0x1, %g2 | ||
253 | andncc %g2, 0x1, %g0 | ||
254 | be 1f | ||
255 | lda [%g1] ASI_PTE, %g2 | ||
256 | |||
257 | /* Second page is in vma hole */ | ||
258 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
259 | wr %t_wim, 0x0, %wim | ||
260 | |||
261 | 1: | ||
262 | srl %g2, 29, %g2 | ||
263 | andcc %g2, 0x4, %g0 | ||
264 | bne sun4c_rett_onepage | ||
265 | lda [%fp] ASI_PTE, %g2 | ||
266 | |||
267 | /* Second page has bad perms */ | ||
268 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
269 | wr %t_wim, 0x0, %wim | ||
270 | |||
271 | sun4c_rett_onepage: | ||
272 | srl %g2, 29, %g2 | ||
273 | andcc %g2, 0x4, %g0 | ||
274 | bne,a 1f | ||
275 | restore %g0, %g0, %g0 | ||
276 | |||
277 | /* A page had bad page permissions, losing... */ | ||
278 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
279 | wr %t_wim, 0x0, %wim | ||
280 | |||
281 | /* Whee, things are ok, load the window and continue. */ | ||
282 | 1: | ||
283 | LOAD_WINDOW(sp) | ||
284 | |||
285 | b ret_trap_userwins_ok | ||
286 | save %g0, %g0, %g0 | ||
287 | |||
288 | .globl srmmu_rett_stackchk | ||
289 | srmmu_rett_stackchk: | ||
290 | bne ret_trap_user_stack_is_bolixed | ||
291 | sethi %hi(PAGE_OFFSET), %g1 | ||
292 | cmp %g1, %fp | ||
293 | bleu ret_trap_user_stack_is_bolixed | ||
294 | mov AC_M_SFSR, %g1 | ||
295 | lda [%g1] ASI_M_MMUREGS, %g0 | ||
296 | |||
297 | lda [%g0] ASI_M_MMUREGS, %g1 | ||
298 | or %g1, 0x2, %g1 | ||
299 | sta %g1, [%g0] ASI_M_MMUREGS | ||
300 | |||
301 | restore %g0, %g0, %g0 | ||
302 | |||
303 | LOAD_WINDOW(sp) | ||
304 | |||
305 | save %g0, %g0, %g0 | ||
306 | |||
307 | andn %g1, 0x2, %g1 | ||
308 | sta %g1, [%g0] ASI_M_MMUREGS | ||
309 | |||
310 | mov AC_M_SFAR, %g2 | ||
311 | lda [%g2] ASI_M_MMUREGS, %g2 | ||
312 | |||
313 | mov AC_M_SFSR, %g1 | ||
314 | lda [%g1] ASI_M_MMUREGS, %g1 | ||
315 | andcc %g1, 0x2, %g0 | ||
316 | be ret_trap_userwins_ok | ||
317 | nop | ||
318 | |||
319 | b,a ret_trap_user_stack_is_bolixed | ||