Merge HEAD from ../scsi-iscsi-2.6
[linux-2.6] / arch / sparc64 / kernel / winfixup.S
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 spitfire_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            spitfire_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            spitfire_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