diff options
Diffstat (limited to 'arch/sparc64/kernel/winfixup.S')
-rw-r--r-- | arch/sparc64/kernel/winfixup.S | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S new file mode 100644 index 000000000000..dfbc7e0dcf70 --- /dev/null +++ b/arch/sparc64/kernel/winfixup.S | |||
@@ -0,0 +1,417 @@ | |||
1 | /* $Id: winfixup.S,v 1.30 2002/02/09 19:49:30 davem Exp $ | ||
2 | * | ||
3 | * winfixup.S: Handle cases where user stack pointer is found to be bogus. | ||
4 | * | ||
5 | * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) | ||
6 | */ | ||
7 | |||
8 | #include <asm/asi.h> | ||
9 | #include <asm/head.h> | ||
10 | #include <asm/page.h> | ||
11 | #include <asm/ptrace.h> | ||
12 | #include <asm/processor.h> | ||
13 | #include <asm/spitfire.h> | ||
14 | #include <asm/thread_info.h> | ||
15 | |||
16 | .text | ||
17 | |||
18 | set_pcontext: | ||
19 | cplus_winfixup_insn_1: | ||
20 | sethi %hi(0), %l1 | ||
21 | mov PRIMARY_CONTEXT, %g1 | ||
22 | sllx %l1, 32, %l1 | ||
23 | cplus_winfixup_insn_2: | ||
24 | sethi %hi(0), %g2 | ||
25 | or %l1, %g2, %l1 | ||
26 | stxa %l1, [%g1] ASI_DMMU | ||
27 | flush %g6 | ||
28 | retl | ||
29 | nop | ||
30 | |||
31 | cplus_wfinsn_1: | ||
32 | sethi %uhi(CTX_CHEETAH_PLUS_NUC), %l1 | ||
33 | cplus_wfinsn_2: | ||
34 | sethi %hi(CTX_CHEETAH_PLUS_CTX0), %g2 | ||
35 | |||
36 | .align 32 | ||
37 | |||
38 | /* Here are the rules, pay attention. | ||
39 | * | ||
40 | * The kernel is disallowed from touching user space while | ||
41 | * the trap level is greater than zero, except for from within | ||
42 | * the window spill/fill handlers. This must be followed | ||
43 | * so that we can easily detect the case where we tried to | ||
44 | * spill/fill with a bogus (or unmapped) user stack pointer. | ||
45 | * | ||
46 | * These are layed out in a special way for cache reasons, | ||
47 | * don't touch... | ||
48 | */ | ||
49 | .globl fill_fixup, spill_fixup | ||
50 | fill_fixup: | ||
51 | rdpr %tstate, %g1 | ||
52 | andcc %g1, TSTATE_PRIV, %g0 | ||
53 | or %g4, FAULT_CODE_WINFIXUP, %g4 | ||
54 | be,pt %xcc, window_scheisse_from_user_common | ||
55 | and %g1, TSTATE_CWP, %g1 | ||
56 | |||
57 | /* This is the extremely complex case, but it does happen from | ||
58 | * time to time if things are just right. Essentially the restore | ||
59 | * done in rtrap right before going back to user mode, with tl=1 | ||
60 | * and that levels trap stack registers all setup, took a fill trap, | ||
61 | * the user stack was not mapped in the tlb, and tlb miss occurred, | ||
62 | * the pte found was not valid, and a simple ref bit watch update | ||
63 | * could not satisfy the miss, so we got here. | ||
64 | * | ||
65 | * We must carefully unwind the state so we get back to tl=0, preserve | ||
66 | * all the register values we were going to give to the user. Luckily | ||
67 | * most things are where they need to be, we also have the address | ||
68 | * which triggered the fault handy as well. | ||
69 | * | ||
70 | * Also note that we must preserve %l5 and %l6. If the user was | ||
71 | * returning from a system call, we must make it look this way | ||
72 | * after we process the fill fault on the users stack. | ||
73 | * | ||
74 | * First, get into the window where the original restore was executed. | ||
75 | */ | ||
76 | |||
77 | rdpr %wstate, %g2 ! Grab user mode wstate. | ||
78 | wrpr %g1, %cwp ! Get into the right window. | ||
79 | sll %g2, 3, %g2 ! NORMAL-->OTHER | ||
80 | |||
81 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | ||
82 | wrpr %g2, 0x0, %wstate ! This must be consistent. | ||
83 | wrpr %g0, 0x0, %otherwin ! We know this. | ||
84 | call set_pcontext ! Change contexts... | ||
85 | nop | ||
86 | rdpr %pstate, %l1 ! Prepare to change globals. | ||
87 | mov %g6, %o7 ! Get current. | ||
88 | |||
89 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | ||
90 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
91 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
92 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
93 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
94 | mov %o7, %g6 | ||
95 | ldx [%g6 + TI_TASK], %g4 | ||
96 | #ifdef CONFIG_SMP | ||
97 | mov TSB_REG, %g1 | ||
98 | ldxa [%g1] ASI_IMMU, %g5 | ||
99 | #endif | ||
100 | |||
101 | /* This is the same as below, except we handle this a bit special | ||
102 | * since we must preserve %l5 and %l6, see comment above. | ||
103 | */ | ||
104 | call do_sparc64_fault | ||
105 | add %sp, PTREGS_OFF, %o0 | ||
106 | ba,pt %xcc, rtrap | ||
107 | nop ! yes, nop is correct | ||
108 | |||
109 | /* Be very careful about usage of the alternate globals here. | ||
110 | * You cannot touch %g4/%g5 as that has the fault information | ||
111 | * should this be from usermode. Also be careful for the case | ||
112 | * where we get here from the save instruction in etrap.S when | ||
113 | * coming from either user or kernel (does not matter which, it | ||
114 | * is the same problem in both cases). Essentially this means | ||
115 | * do not touch %g7 or %g2 so we handle the two cases fine. | ||
116 | */ | ||
117 | spill_fixup: | ||
118 | ldx [%g6 + TI_FLAGS], %g1 | ||
119 | andcc %g1, _TIF_32BIT, %g0 | ||
120 | ldub [%g6 + TI_WSAVED], %g1 | ||
121 | |||
122 | sll %g1, 3, %g3 | ||
123 | add %g6, %g3, %g3 | ||
124 | stx %sp, [%g3 + TI_RWIN_SPTRS] | ||
125 | sll %g1, 7, %g3 | ||
126 | bne,pt %xcc, 1f | ||
127 | add %g6, %g3, %g3 | ||
128 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
129 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | ||
130 | |||
131 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | ||
132 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | ||
133 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | ||
134 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | ||
135 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | ||
136 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | ||
137 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | ||
138 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | ||
139 | |||
140 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | ||
141 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | ||
142 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | ||
143 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | ||
144 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | ||
145 | b,pt %xcc, 2f | ||
146 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | ||
147 | 1: stw %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
148 | |||
149 | stw %l1, [%g3 + TI_REG_WINDOW + 0x04] | ||
150 | stw %l2, [%g3 + TI_REG_WINDOW + 0x08] | ||
151 | stw %l3, [%g3 + TI_REG_WINDOW + 0x0c] | ||
152 | stw %l4, [%g3 + TI_REG_WINDOW + 0x10] | ||
153 | stw %l5, [%g3 + TI_REG_WINDOW + 0x14] | ||
154 | stw %l6, [%g3 + TI_REG_WINDOW + 0x18] | ||
155 | stw %l7, [%g3 + TI_REG_WINDOW + 0x1c] | ||
156 | stw %i0, [%g3 + TI_REG_WINDOW + 0x20] | ||
157 | |||
158 | stw %i1, [%g3 + TI_REG_WINDOW + 0x24] | ||
159 | stw %i2, [%g3 + TI_REG_WINDOW + 0x28] | ||
160 | stw %i3, [%g3 + TI_REG_WINDOW + 0x2c] | ||
161 | stw %i4, [%g3 + TI_REG_WINDOW + 0x30] | ||
162 | stw %i5, [%g3 + TI_REG_WINDOW + 0x34] | ||
163 | stw %i6, [%g3 + TI_REG_WINDOW + 0x38] | ||
164 | stw %i7, [%g3 + TI_REG_WINDOW + 0x3c] | ||
165 | 2: add %g1, 1, %g1 | ||
166 | |||
167 | stb %g1, [%g6 + TI_WSAVED] | ||
168 | rdpr %tstate, %g1 | ||
169 | andcc %g1, TSTATE_PRIV, %g0 | ||
170 | saved | ||
171 | and %g1, TSTATE_CWP, %g1 | ||
172 | be,pn %xcc, window_scheisse_from_user_common | ||
173 | mov FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4 | ||
174 | retry | ||
175 | |||
176 | window_scheisse_from_user_common: | ||
177 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
178 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
179 | wrpr %g1, %cwp | ||
180 | ba,pt %xcc, etrap | ||
181 | rd %pc, %g7 | ||
182 | call do_sparc64_fault | ||
183 | add %sp, PTREGS_OFF, %o0 | ||
184 | ba,a,pt %xcc, rtrap_clr_l6 | ||
185 | |||
186 | .globl winfix_mna, fill_fixup_mna, spill_fixup_mna | ||
187 | winfix_mna: | ||
188 | andn %g3, 0x7f, %g3 | ||
189 | add %g3, 0x78, %g3 | ||
190 | wrpr %g3, %tnpc | ||
191 | done | ||
192 | fill_fixup_mna: | ||
193 | rdpr %tstate, %g1 | ||
194 | andcc %g1, TSTATE_PRIV, %g0 | ||
195 | be,pt %xcc, window_mna_from_user_common | ||
196 | and %g1, TSTATE_CWP, %g1 | ||
197 | |||
198 | /* Please, see fill_fixup commentary about why we must preserve | ||
199 | * %l5 and %l6 to preserve absolute correct semantics. | ||
200 | */ | ||
201 | rdpr %wstate, %g2 ! Grab user mode wstate. | ||
202 | wrpr %g1, %cwp ! Get into the right window. | ||
203 | sll %g2, 3, %g2 ! NORMAL-->OTHER | ||
204 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | ||
205 | |||
206 | wrpr %g2, 0x0, %wstate ! This must be consistent. | ||
207 | wrpr %g0, 0x0, %otherwin ! We know this. | ||
208 | call set_pcontext ! Change contexts... | ||
209 | nop | ||
210 | rdpr %pstate, %l1 ! Prepare to change globals. | ||
211 | mov %g4, %o2 ! Setup args for | ||
212 | mov %g5, %o1 ! final call to mem_address_unaligned. | ||
213 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | ||
214 | |||
215 | mov %g6, %o7 ! Stash away current. | ||
216 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
217 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
218 | mov %o7, %g6 ! Get current back. | ||
219 | ldx [%g6 + TI_TASK], %g4 ! Finish it. | ||
220 | #ifdef CONFIG_SMP | ||
221 | mov TSB_REG, %g1 | ||
222 | ldxa [%g1] ASI_IMMU, %g5 | ||
223 | #endif | ||
224 | call mem_address_unaligned | ||
225 | add %sp, PTREGS_OFF, %o0 | ||
226 | |||
227 | b,pt %xcc, rtrap | ||
228 | nop ! yes, the nop is correct | ||
229 | spill_fixup_mna: | ||
230 | ldx [%g6 + TI_FLAGS], %g1 | ||
231 | andcc %g1, _TIF_32BIT, %g0 | ||
232 | ldub [%g6 + TI_WSAVED], %g1 | ||
233 | sll %g1, 3, %g3 | ||
234 | add %g6, %g3, %g3 | ||
235 | stx %sp, [%g3 + TI_RWIN_SPTRS] | ||
236 | |||
237 | sll %g1, 7, %g3 | ||
238 | bne,pt %xcc, 1f | ||
239 | add %g6, %g3, %g3 | ||
240 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
241 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | ||
242 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | ||
243 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | ||
244 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | ||
245 | |||
246 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | ||
247 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | ||
248 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | ||
249 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | ||
250 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | ||
251 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | ||
252 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | ||
253 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | ||
254 | |||
255 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | ||
256 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | ||
257 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | ||
258 | b,pt %xcc, 2f | ||
259 | add %g1, 1, %g1 | ||
260 | 1: std %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
261 | std %l2, [%g3 + TI_REG_WINDOW + 0x08] | ||
262 | std %l4, [%g3 + TI_REG_WINDOW + 0x10] | ||
263 | |||
264 | std %l6, [%g3 + TI_REG_WINDOW + 0x18] | ||
265 | std %i0, [%g3 + TI_REG_WINDOW + 0x20] | ||
266 | std %i2, [%g3 + TI_REG_WINDOW + 0x28] | ||
267 | std %i4, [%g3 + TI_REG_WINDOW + 0x30] | ||
268 | std %i6, [%g3 + TI_REG_WINDOW + 0x38] | ||
269 | add %g1, 1, %g1 | ||
270 | 2: stb %g1, [%g6 + TI_WSAVED] | ||
271 | rdpr %tstate, %g1 | ||
272 | |||
273 | andcc %g1, TSTATE_PRIV, %g0 | ||
274 | saved | ||
275 | be,pn %xcc, window_mna_from_user_common | ||
276 | and %g1, TSTATE_CWP, %g1 | ||
277 | retry | ||
278 | window_mna_from_user_common: | ||
279 | wrpr %g1, %cwp | ||
280 | sethi %hi(109f), %g7 | ||
281 | ba,pt %xcc, etrap | ||
282 | 109: or %g7, %lo(109b), %g7 | ||
283 | mov %l4, %o2 | ||
284 | mov %l5, %o1 | ||
285 | call mem_address_unaligned | ||
286 | add %sp, PTREGS_OFF, %o0 | ||
287 | ba,pt %xcc, rtrap | ||
288 | clr %l6 | ||
289 | |||
290 | /* These are only needed for 64-bit mode processes which | ||
291 | * put their stack pointer into the VPTE area and there | ||
292 | * happens to be a VPTE tlb entry mapped there during | ||
293 | * a spill/fill trap to that stack frame. | ||
294 | */ | ||
295 | .globl winfix_dax, fill_fixup_dax, spill_fixup_dax | ||
296 | winfix_dax: | ||
297 | andn %g3, 0x7f, %g3 | ||
298 | add %g3, 0x74, %g3 | ||
299 | wrpr %g3, %tnpc | ||
300 | done | ||
301 | fill_fixup_dax: | ||
302 | rdpr %tstate, %g1 | ||
303 | andcc %g1, TSTATE_PRIV, %g0 | ||
304 | be,pt %xcc, window_dax_from_user_common | ||
305 | and %g1, TSTATE_CWP, %g1 | ||
306 | |||
307 | /* Please, see fill_fixup commentary about why we must preserve | ||
308 | * %l5 and %l6 to preserve absolute correct semantics. | ||
309 | */ | ||
310 | rdpr %wstate, %g2 ! Grab user mode wstate. | ||
311 | wrpr %g1, %cwp ! Get into the right window. | ||
312 | sll %g2, 3, %g2 ! NORMAL-->OTHER | ||
313 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | ||
314 | |||
315 | wrpr %g2, 0x0, %wstate ! This must be consistent. | ||
316 | wrpr %g0, 0x0, %otherwin ! We know this. | ||
317 | call set_pcontext ! Change contexts... | ||
318 | nop | ||
319 | rdpr %pstate, %l1 ! Prepare to change globals. | ||
320 | mov %g4, %o1 ! Setup args for | ||
321 | mov %g5, %o2 ! final call to data_access_exception. | ||
322 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | ||
323 | |||
324 | mov %g6, %o7 ! Stash away current. | ||
325 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
326 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
327 | mov %o7, %g6 ! Get current back. | ||
328 | ldx [%g6 + TI_TASK], %g4 ! Finish it. | ||
329 | #ifdef CONFIG_SMP | ||
330 | mov TSB_REG, %g1 | ||
331 | ldxa [%g1] ASI_IMMU, %g5 | ||
332 | #endif | ||
333 | call data_access_exception | ||
334 | add %sp, PTREGS_OFF, %o0 | ||
335 | |||
336 | b,pt %xcc, rtrap | ||
337 | nop ! yes, the nop is correct | ||
338 | spill_fixup_dax: | ||
339 | ldx [%g6 + TI_FLAGS], %g1 | ||
340 | andcc %g1, _TIF_32BIT, %g0 | ||
341 | ldub [%g6 + TI_WSAVED], %g1 | ||
342 | sll %g1, 3, %g3 | ||
343 | add %g6, %g3, %g3 | ||
344 | stx %sp, [%g3 + TI_RWIN_SPTRS] | ||
345 | |||
346 | sll %g1, 7, %g3 | ||
347 | bne,pt %xcc, 1f | ||
348 | add %g6, %g3, %g3 | ||
349 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
350 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | ||
351 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | ||
352 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | ||
353 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | ||
354 | |||
355 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | ||
356 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | ||
357 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | ||
358 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | ||
359 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | ||
360 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | ||
361 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | ||
362 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | ||
363 | |||
364 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | ||
365 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | ||
366 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | ||
367 | b,pt %xcc, 2f | ||
368 | add %g1, 1, %g1 | ||
369 | 1: std %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
370 | std %l2, [%g3 + TI_REG_WINDOW + 0x08] | ||
371 | std %l4, [%g3 + TI_REG_WINDOW + 0x10] | ||
372 | |||
373 | std %l6, [%g3 + TI_REG_WINDOW + 0x18] | ||
374 | std %i0, [%g3 + TI_REG_WINDOW + 0x20] | ||
375 | std %i2, [%g3 + TI_REG_WINDOW + 0x28] | ||
376 | std %i4, [%g3 + TI_REG_WINDOW + 0x30] | ||
377 | std %i6, [%g3 + TI_REG_WINDOW + 0x38] | ||
378 | add %g1, 1, %g1 | ||
379 | 2: stb %g1, [%g6 + TI_WSAVED] | ||
380 | rdpr %tstate, %g1 | ||
381 | |||
382 | andcc %g1, TSTATE_PRIV, %g0 | ||
383 | saved | ||
384 | be,pn %xcc, window_dax_from_user_common | ||
385 | and %g1, TSTATE_CWP, %g1 | ||
386 | retry | ||
387 | window_dax_from_user_common: | ||
388 | wrpr %g1, %cwp | ||
389 | sethi %hi(109f), %g7 | ||
390 | ba,pt %xcc, etrap | ||
391 | 109: or %g7, %lo(109b), %g7 | ||
392 | mov %l4, %o1 | ||
393 | mov %l5, %o2 | ||
394 | call data_access_exception | ||
395 | add %sp, PTREGS_OFF, %o0 | ||
396 | ba,pt %xcc, rtrap | ||
397 | clr %l6 | ||
398 | |||
399 | |||
400 | .globl cheetah_plus_patch_winfixup | ||
401 | cheetah_plus_patch_winfixup: | ||
402 | sethi %hi(cplus_wfinsn_1), %o0 | ||
403 | sethi %hi(cplus_winfixup_insn_1), %o2 | ||
404 | lduw [%o0 + %lo(cplus_wfinsn_1)], %o1 | ||
405 | or %o2, %lo(cplus_winfixup_insn_1), %o2 | ||
406 | stw %o1, [%o2] | ||
407 | flush %o2 | ||
408 | |||
409 | sethi %hi(cplus_wfinsn_2), %o0 | ||
410 | sethi %hi(cplus_winfixup_insn_2), %o2 | ||
411 | lduw [%o0 + %lo(cplus_wfinsn_2)], %o1 | ||
412 | or %o2, %lo(cplus_winfixup_insn_2), %o2 | ||
413 | stw %o1, [%o2] | ||
414 | flush %o2 | ||
415 | |||
416 | retl | ||
417 | nop | ||