VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / sparc64 / lib / U3copy_from_user.S
1 /* U3copy_from_user.S: UltraSparc-III optimized copy from userspace.
2  *
3  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
4  */
5
6 #include <asm/visasm.h>
7 #include <asm/asi.h>
8 #include <asm/dcu.h>
9 #include <asm/spitfire.h>
10
11 #define XCC xcc
12
13 #define EXNV_RAW(x,y,a,b)               \
14 98:     x,y;                            \
15         .section .fixup;                \
16         .align 4;                       \
17 99:     ba U3cfu_fixup;                 \
18          a, b, %o1;                     \
19         .section __ex_table;            \
20         .align 4;                       \
21         .word 98b, 99b;                 \
22         .text;                          \
23         .align 4;
24 #define EXNV(x,y,a,b)                   \
25 98:     x,y;                            \
26         .section .fixup;                \
27         .align 4;                       \
28 99:     add %o1, %o3, %o0;              \
29         ba U3cfu_fixup;                 \
30          a, b, %o1;                     \
31         .section __ex_table;            \
32         .align 4;                       \
33         .word 98b, 99b;                 \
34         .text;                          \
35         .align 4;
36 #define EXNV4(x,y,a,b)                  \
37 98:     x,y;                            \
38         .section .fixup;                \
39         .align 4;                       \
40 99:     add %o1, %o3, %o0;              \
41         a, b, %o1;                      \
42         ba U3cfu_fixup;                 \
43          add %o1, 4, %o1;               \
44         .section __ex_table;            \
45         .align 4;                       \
46         .word 98b, 99b;                 \
47         .text;                          \
48         .align 4;
49 #define EXNV8(x,y,a,b)                  \
50 98:     x,y;                            \
51         .section .fixup;                \
52         .align 4;                       \
53 99:     add %o1, %o3, %o0;              \
54         a, b, %o1;                      \
55         ba U3cfu_fixup;                 \
56          add %o1, 8, %o1;               \
57         .section __ex_table;            \
58         .align 4;                       \
59         .word 98b, 99b;                 \
60         .text;                          \
61         .align 4;
62 #define EX(x,y,a,b)                     \
63 98:     x,y;                            \
64         .section .fixup;                \
65         .align 4;                       \
66 99:     VISExitHalf;                    \
67         ba U3cfu_fixup;                 \
68          a, b, %o1;                     \
69         .section __ex_table;            \
70         .align 4;                       \
71         .word 98b, 99b;                 \
72         .text;                          \
73         .align 4;
74 #define EX2(x,y)                        \
75 98:     x,y;                            \
76         .section .fixup;                \
77         .align 4;                       \
78 99:     VISExitHalf;                    \
79         and %o2, (0x40 - 1), %o1;       \
80         add %o1, %o4, %o1;              \
81         ba U3cfu_fixup;                 \
82          add %o1, 0x1c0, %o1;           \
83         .section __ex_table;            \
84         .align 4;                       \
85         .word 98b, 99b;                 \
86         .text;                          \
87         .align 4;
88 #define EX3(x,y)                        \
89 98:     x,y;                            \
90         .section .fixup;                \
91         .align 4;                       \
92 99:     VISExitHalf;                    \
93         and %o2, (0x40 - 1), %o1;       \
94         sll %g3, 6, %g3;                \
95         add %o1, 0x80, %o1;             \
96         ba U3cfu_fixup;                 \
97          add %o1, %g3, %o1;             \
98         .section __ex_table;            \
99         .align 4;                       \
100         .word 98b, 99b;                 \
101         .text;                          \
102         .align 4;
103 #define EX4(x,y)                        \
104 98:     x,y;                            \
105         .section .fixup;                \
106         .align 4;                       \
107 99:     VISExitHalf;                    \
108         and %o2, (0x40 - 1), %o1;       \
109         add %o1, 0x40, %o1;             \
110         ba U3cfu_fixup;                 \
111          add %o1, %g3, %o1;             \
112         .section __ex_table;            \
113         .align 4;                       \
114         .word 98b, 99b;                 \
115         .text;                          \
116         .align 4;
117
118         .register       %g2,#scratch
119         .register       %g3,#scratch
120
121         /* Special/non-trivial issues of this code:
122          *
123          * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
124          * 2) Only low 32 FPU registers are used so that only the
125          *    lower half of the FPU register set is dirtied by this
126          *    code.  This is especially important in the kernel.
127          * 3) This code never prefetches cachelines past the end
128          *    of the source buffer.
129          */
130
131         .text
132         .align  32
133
134         /* The cheetah's flexible spine, oversized liver, enlarged heart,
135          * slender muscular body, and claws make it the swiftest hunter
136          * in Africa and the fastest animal on land.  Can reach speeds
137          * of up to 2.4GB per second.
138          */
139
140         .globl  U3copy_from_user
141 U3copy_from_user:       /* %o0=dst, %o1=src, %o2=len */
142         cmp             %o2, 0
143         be,pn           %XCC, 85f
144          or             %o0, %o1, %o3
145         cmp             %o2, 16
146         bleu,a,pn       %XCC, 80f
147          or             %o3, %o2, %o3
148
149         cmp             %o2, 256
150         blu,pt          %XCC, 70f
151          andcc          %o3, 0x7, %g0
152
153         ba,pt           %xcc, 1f
154          andcc          %o0, 0x3f, %g2
155
156         /* Here len >= 256 and condition codes reflect execution
157          * of "andcc %o0, 0x7, %g2", done by caller.
158          */
159         .align          64
160 1:
161         /* Is 'dst' already aligned on an 64-byte boundary? */
162         be,pt           %XCC, 2f
163
164         /* Compute abs((dst & 0x3f) - 0x40) into %g2.  This is the number
165          * of bytes to copy to make 'dst' 64-byte aligned.  We pre-
166          * subtract this from 'len'.
167          */
168          sub            %g2, 0x40, %g2
169         sub             %g0, %g2, %g2
170         sub             %o2, %g2, %o2
171
172         /* Copy %g2 bytes from src to dst, one byte at a time. */
173 1:      EXNV_RAW(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)
174         add             %o1, 0x1, %o1
175         add             %o0, 0x1, %o0
176         subcc           %g2, 0x1, %g2
177
178         bg,pt           %XCC, 1b
179          stb            %o3, [%o0 + -1]
180
181 2:      VISEntryHalf
182         and             %o1, 0x7, %g1
183         ba,pt           %xcc, 1f
184          alignaddr      %o1, %g0, %o1
185
186         .align          64
187 1:
188         membar          #StoreLoad | #StoreStore | #LoadStore
189         prefetcha       [%o1 + 0x000] %asi, #one_read
190         prefetcha       [%o1 + 0x040] %asi, #one_read
191         andn            %o2, (0x40 - 1), %o4
192         prefetcha       [%o1 + 0x080] %asi, #one_read
193         prefetcha       [%o1 + 0x0c0] %asi, #one_read
194         EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0)
195         prefetcha       [%o1 + 0x100] %asi, #one_read
196         EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0)
197         prefetcha       [%o1 + 0x140] %asi, #one_read
198         EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0)
199         prefetcha       [%o1 + 0x180] %asi, #one_read
200         faligndata      %f0, %f2, %f16
201         EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0)
202         faligndata      %f2, %f4, %f18
203         EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0)
204         faligndata      %f4, %f6, %f20
205         EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0)
206         faligndata      %f6, %f8, %f22
207
208         EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0)
209         faligndata      %f8, %f10, %f24
210         EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0)
211         faligndata      %f10, %f12, %f26
212         EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0)
213
214         sub             %o4, 0x80, %o4
215         add             %o1, 0x40, %o1
216         ba,pt           %xcc, 1f
217          srl            %o4, 6, %o3
218
219         .align          64
220 1:
221         EX3(ldda [%o1 + 0x008] %asi, %f2)
222         faligndata      %f12, %f14, %f28
223         EX3(ldda [%o1 + 0x010] %asi, %f4)
224         faligndata      %f14, %f0, %f30
225         stda            %f16, [%o0] ASI_BLK_P
226         EX3(ldda [%o1 + 0x018] %asi, %f6)
227         faligndata      %f0, %f2, %f16
228
229         EX3(ldda [%o1 + 0x020] %asi, %f8)
230         faligndata      %f2, %f4, %f18
231         EX3(ldda [%o1 + 0x028] %asi, %f10)
232         faligndata      %f4, %f6, %f20
233         EX3(ldda [%o1 + 0x030] %asi, %f12)
234         faligndata      %f6, %f8, %f22
235         EX3(ldda [%o1 + 0x038] %asi, %f14)
236         faligndata      %f8, %f10, %f24
237
238         EX3(ldda [%o1 + 0x040] %asi, %f0)
239         prefetcha       [%o1 + 0x180] %asi, #one_read
240         faligndata      %f10, %f12, %f26
241         subcc           %o3, 0x01, %o3
242         add             %o1, 0x40, %o1
243         bg,pt           %XCC, 1b
244          add            %o0, 0x40, %o0
245
246         /* Finally we copy the last full 64-byte block. */
247         EX3(ldda [%o1 + 0x008] %asi, %f2)
248         faligndata      %f12, %f14, %f28
249         EX3(ldda [%o1 + 0x010] %asi, %f4)
250         faligndata      %f14, %f0, %f30
251         stda            %f16, [%o0] ASI_BLK_P
252         EX3(ldda [%o1 + 0x018] %asi, %f6)
253         faligndata      %f0, %f2, %f16
254         EX3(ldda [%o1 + 0x020] %asi, %f8)
255         faligndata      %f2, %f4, %f18
256         EX3(ldda [%o1 + 0x028] %asi, %f10)
257         faligndata      %f4, %f6, %f20
258         EX3(ldda [%o1 + 0x030] %asi, %f12)
259         faligndata      %f6, %f8, %f22
260         EX3(ldda [%o1 + 0x038] %asi, %f14)
261         faligndata      %f8, %f10, %f24
262         cmp             %g1, 0
263         be,pt           %XCC, 1f
264          add            %o0, 0x40, %o0
265         EX4(ldda [%o1 + 0x040] %asi, %f0)
266 1:      faligndata      %f10, %f12, %f26
267         faligndata      %f12, %f14, %f28
268         faligndata      %f14, %f0, %f30
269         stda            %f16, [%o0] ASI_BLK_P
270         add             %o0, 0x40, %o0
271         add             %o1, 0x40, %o1
272
273         membar          #Sync
274
275         /* Now we copy the (len modulo 64) bytes at the end.
276          * Note how we borrow the %f0 loaded above.
277          *
278          * Also notice how this code is careful not to perform a
279          * load past the end of the src buffer.
280          */
281         and             %o2, 0x3f, %o2
282         andcc           %o2, 0x38, %g2
283         be,pn           %XCC, 10f
284          subcc          %g2, 0x8, %g2
285         be,pn           %XCC, 10f
286          cmp            %g1, 0
287
288         be,a,pt         %XCC, 1f
289          EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0)
290
291 1:      EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0)
292         add             %o1, 0x8, %o1
293         sub             %o2, 0x8, %o2
294         subcc           %g2, 0x8, %g2
295         faligndata      %f0, %f2, %f8
296         std             %f8, [%o0 + 0x00]
297         be,pn           %XCC, 10f
298          add            %o0, 0x8, %o0
299         EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0)
300         add             %o1, 0x8, %o1
301         sub             %o2, 0x8, %o2
302         subcc           %g2, 0x8, %g2
303         faligndata      %f2, %f0, %f8
304         std             %f8, [%o0 + 0x00]
305         bne,pn          %XCC, 1b
306          add            %o0, 0x8, %o0
307
308         /* If anything is left, we copy it one byte at a time.
309          * Note that %g1 is (src & 0x3) saved above before the
310          * alignaddr was performed.
311          */
312 10:
313         cmp             %o2, 0
314         add             %o1, %g1, %o1
315         VISExitHalf
316         be,pn           %XCC, 85f
317          sub            %o0, %o1, %o3
318
319         andcc           %g1, 0x7, %g0
320         bne,pn          %icc, 90f
321          andcc          %o2, 0x8, %g0
322         be,pt           %icc, 1f
323          nop
324         EXNV(ldxa [%o1] %asi, %o5, add %o2, %g0)
325         stx             %o5, [%o1 + %o3]
326         add             %o1, 0x8, %o1
327
328 1:      andcc           %o2, 0x4, %g0
329         be,pt           %icc, 1f
330          nop
331         EXNV(lduwa [%o1] %asi, %o5, and %o2, 0x7)
332         stw             %o5, [%o1 + %o3]
333         add             %o1, 0x4, %o1
334
335 1:      andcc           %o2, 0x2, %g0
336         be,pt           %icc, 1f
337          nop
338         EXNV(lduha [%o1] %asi, %o5, and %o2, 0x3)
339         sth             %o5, [%o1 + %o3]
340         add             %o1, 0x2, %o1
341
342 1:      andcc           %o2, 0x1, %g0
343         be,pt           %icc, 85f
344          nop
345         EXNV(lduba [%o1] %asi, %o5, and %o2, 0x1)
346         ba,pt           %xcc, 85f
347          stb            %o5, [%o1 + %o3]
348
349 70: /* 16 < len <= 64 */
350         bne,pn          %XCC, 90f
351          sub            %o0, %o1, %o3
352
353         andn            %o2, 0x7, %o4
354         and             %o2, 0x7, %o2
355 1:      subcc           %o4, 0x8, %o4
356         EXNV8(ldxa [%o1] %asi, %o5, add %o2, %o4)
357         stx             %o5, [%o1 + %o3]
358         bgu,pt          %XCC, 1b
359          add            %o1, 0x8, %o1
360         andcc           %o2, 0x4, %g0
361         be,pt           %XCC, 1f
362          nop
363         sub             %o2, 0x4, %o2
364         EXNV4(lduwa [%o1] %asi, %o5, add %o2, %g0)
365         stw             %o5, [%o1 + %o3]
366         add             %o1, 0x4, %o1
367 1:      cmp             %o2, 0
368         be,pt           %XCC, 85f
369          nop
370         ba,pt           %xcc, 90f
371          nop
372
373 80: /* 0 < len <= 16 */
374         andcc           %o3, 0x3, %g0
375         bne,pn          %XCC, 90f
376          sub            %o0, %o1, %o3
377
378 1:
379         subcc           %o2, 4, %o2
380         EXNV(lduwa [%o1] %asi, %g1, add %o2, %g0)
381         stw             %g1, [%o1 + %o3]
382         bgu,pt          %XCC, 1b
383          add            %o1, 4, %o1
384
385 85:     retl
386          clr            %o0
387
388         .align  32
389 90:
390         subcc           %o2, 1, %o2
391         EXNV(lduba [%o1] %asi, %g1, add %o2, %g0)
392         stb             %g1, [%o1 + %o3]
393         bgu,pt          %XCC, 90b
394          add            %o1, 1, %o1
395         retl
396          clr            %o0
397
398 U3cfu_fixup:
399         /* Since this is copy_from_user(), zero out the rest of the
400          * kernel buffer.
401          */
402         cmp             %o1, 0
403         ble,pn          %icc, 2f
404          mov            %o1, %g2
405
406 1:      subcc           %g2, 1, %g2
407         stb             %g0, [%o0]
408         bne,pt          %icc, 1b
409          add            %o0, 1, %o0
410
411 2:      retl
412          mov            %o1, %o0