Correct a bug in the last FPU optimized bcopy commit. The user FPU state
[dragonfly.git] / sys / platform / pc32 / i386 / bcopy.s
1 /*
2  * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $DragonFly: src/sys/platform/pc32/i386/bcopy.s,v 1.2 2004/04/30 00:59:52 dillon Exp $
27  */
28 /*
29  * bcopy(source:%esi, target:%edi, count:%ecx)
30  *
31  *      note: esi, edi, eax, ecx, and edx may be destroyed
32  */
33
34 #include "use_npx.h"
35
36 #include <machine/asmacros.h>
37 #include <machine/cputypes.h>
38 #include <machine/pmap.h>
39 #include <machine/specialreg.h>
40
41 #include "assym.s"
42
43         .text
44
45         /*
46          * If memcpy/bcopy is called as part of a copyin or copyout, the
47          * on-fault routine is set up to do a 'ret'.  We hve to restore
48          * %ebx and return to the copyin/copyout fault handler.
49          */
50 generic_onfault:
51         popl    %ebx
52         addl    $4,%esp         /* skip normal return vector */
53         ret                     /* return to copyin/copyout fault handler */
54
55         /*
56          * GENERIC BCOPY() - COPY DIRECTION CHECK AND FORWARDS COPY
57          *
58          *      Reasonably optimal on all modern machines.
59          */
60
61         SUPERALIGN_TEXT
62 ENTRY(asm_generic_memcpy)       /* memcpy() entry point use optimal copy */
63         pushl   %ebx
64         pushl   $generic_onfault
65         jmp     2f
66
67         SUPERALIGN_TEXT
68 ENTRY(asm_generic_bcopy)
69         pushl   %ebx
70         pushl   $generic_onfault
71         cmpl    %esi,%edi       /* if (edi < esi) fwd copy ok */
72         jb      2f
73         addl    %ecx,%esi
74         cmpl    %esi,%edi       /* if (edi < esi + count) do bkwrds copy */
75         jb      10f
76         subl    %ecx,%esi
77         jmp     2f
78
79         SUPERALIGN_TEXT
80 1:
81         movl    (%esi),%eax
82         movl    4(%esi),%ebx
83         movl    8(%esi),%edx
84         movl    %eax,(%edi)
85         movl    12(%esi),%eax
86         movl    %ebx,4(%edi)
87         movl    16(%esi),%ebx
88         movl    %edx,8(%edi)
89         movl    20(%esi),%edx
90         movl    %eax,12(%edi)
91         movl    24(%esi),%eax
92         movl    %ebx,16(%edi)
93         movl    28(%esi),%ebx
94         movl    %edx,20(%edi)
95         movl    %eax,24(%edi)
96         addl    $32,%esi
97         movl    %ebx,28(%edi)
98         addl    $32,%edi
99 2:
100         subl    $32,%ecx
101         jae     1b
102         addl    $32,%ecx
103         jz      3f
104         cld
105         rep
106         movsb
107 3:
108         addl    $4,%esp
109         popl    %ebx
110         ret
111
112         /*
113          * GENERIC_BCOPY() - BACKWARDS COPY
114          */
115         SUPERALIGN_TEXT
116 10:
117         addl    %ecx,%edi
118         jmp     12f
119
120         SUPERALIGN_TEXT
121 11:
122         movl    -4(%esi),%eax
123         movl    -8(%esi),%ebx
124         movl    -12(%esi),%edx
125         movl    %eax,-4(%edi)
126         movl    -16(%esi),%eax
127         movl    %ebx,-8(%edi)
128         movl    -20(%esi),%ebx
129         movl    %edx,-12(%edi)
130         movl    -24(%esi),%edx
131         movl    %eax,-16(%edi)
132         movl    -28(%esi),%eax
133         movl    %ebx,-20(%edi)
134         movl    -32(%esi),%ebx
135         movl    %edx,-24(%edi)
136         movl    %eax,-28(%edi)
137         subl    $32,%esi
138         movl    %ebx,-32(%edi)
139         subl    $32,%edi
140 12:
141         subl    $32,%ecx
142         jae     11b
143         addl    $32,%ecx
144         jz      13f
145         decl    %esi
146         decl    %edi
147         std
148         rep
149         movsb
150         cld
151 13:
152         addl    $4,%esp
153         popl    %ebx
154         ret
155
156         /*
157          * MMX BCOPY() - COPY DIRECTION CHECK AND FORWARDS COPY
158          *
159          * Reasonably optimal on all modern machines with MMX or SSE2.
160          * XXX But very messy, we need a better way to use fp in the kernel.
161          *
162          * note: esi, edi, eax, ecx, and edx may be destroyed
163          *
164          * In order for the kernel to be able to use the FPU:
165          *
166          *      (1) The kernel may not already be using the fpu
167          *
168          *      (2) If the fpu is owned by the application, we must save
169          *          its state.  If the fpu is not owned by the application
170          *          the application's saved fp state may already exist
171          *          in TD_SAVEFPU.
172          *
173          *      (3) We cannot allow the kernel overwrite the application's
174          *          FPU state with our own, so we allocate space on the
175          *          stack and create a new TD_SAVEFPU, saving the old
176          *          pointer.
177          *          
178          *      (4) While we are using the FP unit, an interrupt may come
179          *          along and preempt us, causing our FP state to be saved.
180          *          We will fault/restore upon resumption.  Our FP state
181          *          will be saved on the stack.
182          *
183          *      (5) To clean up we throw away our FP state and, zero out
184          *          npxthread to indicate that the application's FP state
185          *          is stored in TD_SAVEFPU, and we then restore the original
186          *          TD_SAVEFPU.
187          *
188          *          We do not attempt to restore the application's FP state.
189          *          We set the TS bit to guarentee that the application will
190          *          fault when it next tries to access the FP (to restore its
191          *          state).
192          *
193          *  NOTE: fxsave requires a 16-byte aligned address
194          *
195          *  MMX+XMM (SSE2): Typical on Athlons, later P4s. 128 bit media insn.
196          *  MMX: Typical on XPs and P3s.  64 bit media insn.
197          */
198
199 #define MMX_SAVE_BLOCK(missfunc)                \
200         cmpl    $2048,%ecx ;                    \
201         jb      missfunc ;                      \
202         btsl    $1,PCPU(kernel_fpu_lock) ;      \
203         jc      missfunc ;                      \
204         pushl   %ebx ;                          \
205         pushl   %ebp ;                          \
206         movl    %esp, %ebp ;                    \
207         movl    PCPU(curthread),%edx ;          \
208         movl    TD_SAVEFPU(%edx),%ebx ;         \
209         subl    $512,%esp ;                     \
210         andl    $0xfffffff0,%esp ;              \
211         movl    %esp,TD_SAVEFPU(%edx) ;         \
212         cmpl    %edx,PCPU(npxthread) ;          \
213         jne     100f ;                          \
214         fxsave  0(%ebx) ;                       \
215 100: ;                                          \
216         clts ;                                  \
217         movl    %edx,PCPU(npxthread) ;          \
218         fninit ;                                \
219         pushl   $mmx_onfault
220
221
222 #define MMX_RESTORE_BLOCK                       \
223         addl    $4,%esp ;                       \
224         MMX_RESTORE_BLOCK2
225
226 #define MMX_RESTORE_BLOCK2                      \
227         movl    PCPU(curthread),%edx ;          \
228         movl    $0,PCPU(npxthread) ;            \
229         movl    %ebx,TD_SAVEFPU(%edx) ;         \
230         smsw    %ax ;                           \
231         movl    %ebp,%esp ;                     \
232         orb     $CR0_TS,%al ;                   \
233         popl    %ebp ;                          \
234         lmsw    %ax ;                           \
235         popl    %ebx ;                          \
236         movl    $0,PCPU(kernel_fpu_lock)
237
238         /*
239          * xmm/mmx_onfault routine.  Restore the fpu state, skip the normal
240          * return vector, and return to the caller's on-fault routine
241          * (which was pushed on the callers stack just before he calle us)
242          */
243 mmx_onfault:
244         MMX_RESTORE_BLOCK2
245         addl    $4,%esp
246         ret
247
248         /*
249          * MXX entry points - only support 64 bit media instructions
250          */
251         SUPERALIGN_TEXT
252 ENTRY(asm_mmx_memcpy)           /* memcpy() entry point use optimal copy */
253         MMX_SAVE_BLOCK(asm_generic_memcpy)
254         jmp     5f
255
256         SUPERALIGN_TEXT
257 ENTRY(asm_mmx_bcopy)
258         MMX_SAVE_BLOCK(asm_generic_bcopy)
259         cmpl    %esi,%edi       /* if (edi < esi) fwd copy ok */
260         jb      5f
261         addl    %ecx,%esi
262         cmpl    %esi,%edi       /* if (edi < esi + count) do bkwrds copy */
263         jb      10f
264         subl    %ecx,%esi
265         jmp     5f
266
267         /*
268          * XMM entry points - support 128 bit media instructions
269          */
270         SUPERALIGN_TEXT
271 ENTRY(asm_xmm_memcpy)           /* memcpy() entry point use optimal copy */
272         MMX_SAVE_BLOCK(asm_generic_memcpy)
273         jmp     1f
274
275         SUPERALIGN_TEXT
276 ENTRY(asm_xmm_bcopy)
277         MMX_SAVE_BLOCK(asm_generic_bcopy)
278         cmpl    %esi,%edi       /* if (edi < esi) fwd copy ok */
279         jb      1f
280         addl    %ecx,%esi
281         cmpl    %esi,%edi       /* if (edi < esi + count) do bkwrds copy */
282         jb      10f
283         subl    %ecx,%esi
284 1:
285         movl    %esi,%eax       /* skip xmm if the data is not aligned */
286         andl    $15,%eax
287         jnz     5f
288         movl    %edi,%eax
289         andl    $15,%eax
290         jz      3f
291         jmp     5f
292
293         SUPERALIGN_TEXT
294 2:
295         movdqa  (%esi),%xmm0
296         movdqa  16(%esi),%xmm1
297         movdqa  32(%esi),%xmm2
298         movdqa  48(%esi),%xmm3
299         movdqa  64(%esi),%xmm4
300         movdqa  80(%esi),%xmm5
301         movdqa  96(%esi),%xmm6
302         movdqa  112(%esi),%xmm7
303         /*prefetchnta 128(%esi) 3dNOW */
304         addl    $128,%esi
305
306         /*
307          * movdqa or movntdq can be used.
308          */
309         movdqa  %xmm0,(%edi)
310         movdqa  %xmm1,16(%edi)
311         movdqa  %xmm2,32(%edi)
312         movdqa  %xmm3,48(%edi)
313         movdqa  %xmm4,64(%edi)
314         movdqa  %xmm5,80(%edi)
315         movdqa  %xmm6,96(%edi)
316         movdqa  %xmm7,112(%edi)
317         addl    $128,%edi
318 3:
319         subl    $128,%ecx
320         jae     2b
321         addl    $128,%ecx
322         jz      6f
323         jmp     5f
324         SUPERALIGN_TEXT
325 4:
326         movq    (%esi),%mm0
327         movq    8(%esi),%mm1
328         movq    16(%esi),%mm2
329         movq    24(%esi),%mm3
330         movq    32(%esi),%mm4
331         movq    40(%esi),%mm5
332         movq    48(%esi),%mm6
333         movq    56(%esi),%mm7
334         /*prefetchnta 128(%esi) 3dNOW */
335         addl    $64,%esi
336         movq    %mm0,(%edi)
337         movq    %mm1,8(%edi)
338         movq    %mm2,16(%edi)
339         movq    %mm3,24(%edi)
340         movq    %mm4,32(%edi)
341         movq    %mm5,40(%edi)
342         movq    %mm6,48(%edi)
343         movq    %mm7,56(%edi)
344         addl    $64,%edi
345 5:
346         subl    $64,%ecx
347         jae     4b
348         addl    $64,%ecx
349         jz      6f
350         cld
351         rep
352         movsb
353 6:
354         MMX_RESTORE_BLOCK
355         ret
356
357         /*
358          * GENERIC_BCOPY() - BACKWARDS COPY
359          *
360          * Don't bother using xmm optimizations, just stick with mmx.
361          */
362         SUPERALIGN_TEXT
363 10:
364         addl    %ecx,%edi
365         jmp     12f
366
367         SUPERALIGN_TEXT
368 11:
369         movq    -64(%esi),%mm0
370         movq    -56(%esi),%mm1
371         movq    -48(%esi),%mm2
372         movq    -40(%esi),%mm3
373         movq    -32(%esi),%mm4
374         movq    -24(%esi),%mm5
375         movq    -16(%esi),%mm6
376         movq    -8(%esi),%mm7
377         /*prefetchnta -128(%esi)*/
378         subl    $64,%esi
379         movq    %mm0,-64(%edi)
380         movq    %mm1,-56(%edi)
381         movq    %mm2,-48(%edi)
382         movq    %mm3,-40(%edi)
383         movq    %mm4,-32(%edi)
384         movq    %mm5,-24(%edi)
385         movq    %mm6,-16(%edi)
386         movq    %mm7,-8(%edi)
387         subl    $64,%edi
388 12:
389         subl    $64,%ecx
390         jae     11b
391         addl    $64,%ecx
392         jz      13f
393         decl    %esi
394         decl    %edi
395         std
396         rep
397         movsb
398         cld
399 13:
400         MMX_RESTORE_BLOCK
401         ret
402