907c9718bd865c6984fbaba869fecefd1012d58d
[dragonfly.git] / sys / i386 / 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/i386/i386/Attic/bcopy.s,v 1.5 2004/05/05 19:26:38 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          * bcopyb() is a 'dumb' byte-granular bcopy.  It is only used by
47          * devices which need to bcopy device-mapped memory which cannot
48          * otherwise handle 16 or 32 bit ops.
49          */
50         ALIGN_TEXT
51 ENTRY(bcopyb)
52         pushl   %esi
53         pushl   %edi
54         movl    12(%esp),%esi
55         movl    16(%esp),%edi
56         movl    20(%esp),%ecx
57         movl    %edi,%eax
58         subl    %esi,%eax
59         cmpl    %ecx,%eax                       /* overlapping && src < dst? */
60         jb      1f
61         cld                                     /* nope, copy forwards */
62         rep
63         movsb
64         popl    %edi
65         popl    %esi
66         ret
67
68         ALIGN_TEXT
69 1:
70         addl    %ecx,%edi                       /* copy backwards. */
71         addl    %ecx,%esi
72         decl    %edi
73         decl    %esi
74         std
75         rep
76         movsb
77         popl    %edi
78         popl    %esi
79         cld
80         ret
81
82
83         /*
84          * If memcpy/bcopy is called as part of a copyin or copyout, the
85          * on-fault routine is set up to do a 'ret'.  We have to restore
86          * %ebx and return to the copyin/copyout fault handler.
87          */
88 generic_onfault:
89         popl    %ebx
90         addl    $4,%esp         /* skip normal return vector */
91         ret                     /* return to copyin/copyout fault handler */
92
93         /*
94          * GENERIC BCOPY() - COPY DIRECTION CHECK AND FORWARDS COPY
95          *
96          *      Reasonably optimal on all modern machines.
97          */
98
99         SUPERALIGN_TEXT
100 ENTRY(asm_generic_memcpy)       /* memcpy() entry point use optimal copy */
101         pushl   %ebx
102         pushl   $generic_onfault
103         jmp     2f
104
105         SUPERALIGN_TEXT
106 ENTRY(asm_generic_bcopy)
107         pushl   %ebx
108         pushl   $generic_onfault
109         cmpl    %esi,%edi       /* if (edi < esi) fwd copy ok */
110         jb      2f
111         addl    %ecx,%esi
112         cmpl    %esi,%edi       /* if (edi < esi + count) do bkwrds copy */
113         jb      10f
114         subl    %ecx,%esi
115         jmp     2f
116
117         SUPERALIGN_TEXT
118 1:
119         movl    (%esi),%eax
120         movl    4(%esi),%ebx
121         movl    8(%esi),%edx
122         movl    %eax,(%edi)
123         movl    12(%esi),%eax
124         movl    %ebx,4(%edi)
125         movl    16(%esi),%ebx
126         movl    %edx,8(%edi)
127         movl    20(%esi),%edx
128         movl    %eax,12(%edi)
129         movl    24(%esi),%eax
130         movl    %ebx,16(%edi)
131         movl    28(%esi),%ebx
132         movl    %edx,20(%edi)
133         movl    %eax,24(%edi)
134         addl    $32,%esi
135         movl    %ebx,28(%edi)
136         addl    $32,%edi
137 2:
138         subl    $32,%ecx
139         jae     1b
140         addl    $32,%ecx
141         jz      3f
142         cld
143         rep
144         movsb
145 3:
146         addl    $4,%esp
147         popl    %ebx
148         ret
149
150         /*
151          * GENERIC_BCOPY() - BACKWARDS COPY
152          */
153         SUPERALIGN_TEXT
154 10:
155         addl    %ecx,%edi
156         jmp     12f
157
158         SUPERALIGN_TEXT
159 11:
160         movl    -4(%esi),%eax
161         movl    -8(%esi),%ebx
162         movl    -12(%esi),%edx
163         movl    %eax,-4(%edi)
164         movl    -16(%esi),%eax
165         movl    %ebx,-8(%edi)
166         movl    -20(%esi),%ebx
167         movl    %edx,-12(%edi)
168         movl    -24(%esi),%edx
169         movl    %eax,-16(%edi)
170         movl    -28(%esi),%eax
171         movl    %ebx,-20(%edi)
172         movl    -32(%esi),%ebx
173         movl    %edx,-24(%edi)
174         movl    %eax,-28(%edi)
175         subl    $32,%esi
176         movl    %ebx,-32(%edi)
177         subl    $32,%edi
178 12:
179         subl    $32,%ecx
180         jae     11b
181         addl    $32,%ecx
182         jz      13f
183         decl    %esi
184         decl    %edi
185         std
186         rep
187         movsb
188         cld
189 13:
190         addl    $4,%esp
191         popl    %ebx
192         ret
193
194         /*
195          * MMX BCOPY() - COPY DIRECTION CHECK AND FORWARDS COPY
196          *
197          * note: esi, edi, eax, ecx, and edx are allowed to be destroyed.
198          *
199          * In order for the kernel to be able to use the FPU:
200          *
201          *      (1) The kernel may not already be using the fpu.
202          *
203          *      (2) If the fpu is owned by the application, we must save
204          *          its state.  If the fpu is not owned by the application
205          *          the application's saved fp state may already exist
206          *          in TD_SAVEFPU.
207          *
208          *      (3) We cannot allow the kernel to overwrite the application's
209          *          FPU state with our own, so we make sure the application's
210          *          FPU state has been saved and then point TD_SAVEFPU at a
211          *          temporary fpu save area in the globaldata structure.
212          *          
213          * RACES/ALGORITHM:
214          *
215          *      If gd_npxthread is not NULL we must save the application's
216          *      current FP state to the current save area and then NULL
217          *      out gd_npxthread to interlock against new interruptions
218          *      changing the FP state further.
219          *
220          *      If gd_npxthread is NULL the FP unit is in a known 'safe'
221          *      state and may be used once the new save area is installed.
222          *
223          *      race(1): If an interrupt occurs just prior to calling fxsave
224          *      all that happens is that fxsave gets a npxdna trap, restores
225          *      the app's environment, and immediately traps, restores,
226          *      and saves it again.
227          *
228          *      race(2): No interrupt can safely occur after we NULL-out
229          *      npxthread until we fninit, because the kernel assumes that
230          *      the FP unit is in a safe state when npxthread is NULL.  It's
231          *      more convenient to use a cli sequence here (it is not
232          *      considered to be in the critical path), but a critical
233          *      section would also work.
234          *
235          *      race(3): The FP unit is in a known state (because npxthread
236          *      was either previously NULL or we saved and init'd and made
237          *      it NULL).  This is true even if we are preempted and the
238          *      preempting thread uses the FP unit, because it will be
239          *      fninit's again on return.  ANY STATE WE SAVE TO THE FPU MAY
240          *      BE DESTROYED BY PREEMPTION WHILE NPXTHREAD IS NULL!  However,
241          *      an interrupt occuring inbetween clts and the setting of
242          *      gd_npxthread may set the TS bit again and cause the next
243          *      npxdna() to panic when it sees a non-NULL gd_npxthread.
244          *      
245          *      We can safely set TD_SAVEFPU to point to a new uninitialized
246          *      save area and then set GD_NPXTHREAD to non-NULL.  If an
247          *      interrupt occurs after we set GD_NPXTHREAD, all that happens
248          *      is that the safe FP state gets saved and restored.  We do not
249          *      need to fninit again.
250          *
251          *      We can safely clts after setting up the new save-area, before
252          *      installing gd_npxthread, even if we get preempted just after
253          *      calling clts.  This is because the FP unit will be in a safe
254          *      state while gd_npxthread is NULL.  Setting gd_npxthread will
255          *      simply lock-in that safe-state.  Calling clts saves
256          *      unnecessary trap overhead since we are about to use the FP
257          *      unit anyway and don't need to 'restore' any state prior to
258          *      that first use.
259          *
260          *  MMX+XMM (SSE2): Typical on Athlons, later P4s. 128 bit media insn.
261          *  MMX: Typical on XPs and P3s.  64 bit media insn.
262          */
263
264 #define MMX_SAVE_BLOCK(missfunc)                                        \
265         cmpl    $2048,%ecx ;                                            \
266         jb      missfunc ;                                              \
267         movl    MYCPU,%eax ;                    /* EAX = MYCPU */       \
268         btsl    $1,GD_FPU_LOCK(%eax) ;                                  \
269         jc      missfunc ;                                              \
270         pushl   %ebx ;                                                  \
271         pushl   %ecx ;                                                  \
272         movl    GD_CURTHREAD(%eax),%edx ;       /* EDX = CURTHREAD */   \
273         movl    TD_SAVEFPU(%edx),%ebx ;         /* save app save area */\
274         addl    $TDPRI_CRIT,TD_PRI(%edx) ;                              \
275         cmpl    $0,GD_NPXTHREAD(%eax) ;                                 \
276         je      100f ;                                                  \
277         fxsave  0(%ebx) ;                       /* race(1) */           \
278         movl    $0,GD_NPXTHREAD(%eax) ;         /* interlock intr */    \
279         clts ;                                                          \
280         fninit ;                                /* race(2) */           \
281 100: ;                                                                  \
282         leal    GD_SAVEFPU(%eax),%ecx ;                                 \
283         movl    %ecx,TD_SAVEFPU(%edx) ;                                 \
284         clts ;                                                          \
285         movl    %edx,GD_NPXTHREAD(%eax) ;       /* race(3) */           \
286         subl    $TDPRI_CRIT,TD_PRI(%edx) ;      /* crit_exit() */       \
287         cmpl    $0,GD_REQFLAGS(%eax) ;                                  \
288         je      101f ;                                                  \
289         cmpl    $TDPRI_CRIT,TD_PRI(%edx) ;                              \
290         jge     101f ;                                                  \
291         call    lwkt_yield_quick ;                                      \
292         /* note: eax,ecx,edx destroyed */                               \
293 101: ;                                                                  \
294         movl    (%esp),%ecx ;                                           \
295         movl    $mmx_onfault,(%esp) ;                                   \
296
297         /*
298          * When restoring the application's FP state we must first clear
299          * npxthread to prevent further saves, then restore the pointer
300          * to the app's save area.  We do not have to (and should not)
301          * restore the app's FP state now.  Note that we do not have to
302          * call fninit because our use of the FP guarentees that it is in
303          * a 'safe' state (at least for kernel use).
304          *
305          * NOTE: it is not usually safe to mess with CR0 outside of a
306          * critical section, because TS may get set by a preemptive
307          * interrupt.  However, we *can* race a load/set-ts/store against
308          * an interrupt doing the same thing.
309          */
310
311 #define MMX_RESTORE_BLOCK                       \
312         addl    $4,%esp ;                       \
313         MMX_RESTORE_BLOCK2
314
315 #define MMX_RESTORE_BLOCK2                      \
316         movl    MYCPU,%ecx ;                    \
317         movl    GD_CURTHREAD(%ecx),%edx ;       \
318         movl    $0,GD_NPXTHREAD(%ecx) ;         \
319         movl    %ebx,TD_SAVEFPU(%edx) ;         \
320         smsw    %ax ;                           \
321         popl    %ebx ;                          \
322         orb     $CR0_TS,%al ;                   \
323         lmsw    %ax ;                           \
324         movl    $0,GD_FPU_LOCK(%ecx)
325
326         /*
327          * xmm/mmx_onfault routine.  Restore the fpu state, skip the normal
328          * return vector, and return to the caller's on-fault routine
329          * (which was pushed on the callers stack just before he called us)
330          */
331         ALIGN_TEXT
332 mmx_onfault:
333         MMX_RESTORE_BLOCK2
334         addl    $4,%esp
335         ret
336
337         /*
338          * MXX entry points - only support 64 bit media instructions
339          */
340         SUPERALIGN_TEXT
341 ENTRY(asm_mmx_memcpy)           /* memcpy() entry point use optimal copy */
342         MMX_SAVE_BLOCK(asm_generic_memcpy)
343         jmp     5f
344
345         SUPERALIGN_TEXT
346 ENTRY(asm_mmx_bcopy)
347         MMX_SAVE_BLOCK(asm_generic_bcopy)
348         cmpl    %esi,%edi       /* if (edi < esi) fwd copy ok */
349         jb      5f
350         addl    %ecx,%esi
351         cmpl    %esi,%edi       /* if (edi < esi + count) do bkwrds copy */
352         jb      10f
353         subl    %ecx,%esi
354         jmp     5f
355
356         /*
357          * XMM entry points - support 128 bit media instructions
358          */
359         SUPERALIGN_TEXT
360 ENTRY(asm_xmm_memcpy)           /* memcpy() entry point use optimal copy */
361         MMX_SAVE_BLOCK(asm_generic_memcpy)
362         jmp     1f
363
364         SUPERALIGN_TEXT
365 ENTRY(asm_xmm_bcopy)
366         MMX_SAVE_BLOCK(asm_generic_bcopy)
367         cmpl    %esi,%edi       /* if (edi < esi) fwd copy ok */
368         jb      1f
369         addl    %ecx,%esi
370         cmpl    %esi,%edi       /* if (edi < esi + count) do bkwrds copy */
371         jb      10f
372         subl    %ecx,%esi
373 1:
374         movl    %esi,%eax       /* skip xmm if the data is not aligned */
375         andl    $15,%eax
376         jnz     5f
377         movl    %edi,%eax
378         andl    $15,%eax
379         jz      3f
380         jmp     5f
381
382         SUPERALIGN_TEXT
383 2:
384         movdqa  (%esi),%xmm0
385         movdqa  16(%esi),%xmm1
386         movdqa  32(%esi),%xmm2
387         movdqa  48(%esi),%xmm3
388         movdqa  64(%esi),%xmm4
389         movdqa  80(%esi),%xmm5
390         movdqa  96(%esi),%xmm6
391         movdqa  112(%esi),%xmm7
392         /*prefetchnta 128(%esi) 3dNOW */
393         addl    $128,%esi
394
395         /*
396          * movdqa or movntdq can be used.
397          */
398         movdqa  %xmm0,(%edi)
399         movdqa  %xmm1,16(%edi)
400         movdqa  %xmm2,32(%edi)
401         movdqa  %xmm3,48(%edi)
402         movdqa  %xmm4,64(%edi)
403         movdqa  %xmm5,80(%edi)
404         movdqa  %xmm6,96(%edi)
405         movdqa  %xmm7,112(%edi)
406         addl    $128,%edi
407 3:
408         subl    $128,%ecx
409         jae     2b
410         addl    $128,%ecx
411         jz      6f
412         jmp     5f
413         SUPERALIGN_TEXT
414 4:
415         movq    (%esi),%mm0
416         movq    8(%esi),%mm1
417         movq    16(%esi),%mm2
418         movq    24(%esi),%mm3
419         movq    32(%esi),%mm4
420         movq    40(%esi),%mm5
421         movq    48(%esi),%mm6
422         movq    56(%esi),%mm7
423         /*prefetchnta 128(%esi) 3dNOW */
424         addl    $64,%esi
425         movq    %mm0,(%edi)
426         movq    %mm1,8(%edi)
427         movq    %mm2,16(%edi)
428         movq    %mm3,24(%edi)
429         movq    %mm4,32(%edi)
430         movq    %mm5,40(%edi)
431         movq    %mm6,48(%edi)
432         movq    %mm7,56(%edi)
433         addl    $64,%edi
434 5:
435         subl    $64,%ecx
436         jae     4b
437         addl    $64,%ecx
438         jz      6f
439         cld
440         rep
441         movsb
442 6:
443         MMX_RESTORE_BLOCK
444         ret
445
446         /*
447          * GENERIC_BCOPY() - BACKWARDS COPY
448          *
449          * Don't bother using xmm optimizations, just stick with mmx.
450          */
451         SUPERALIGN_TEXT
452 10:
453         addl    %ecx,%edi
454         jmp     12f
455
456         SUPERALIGN_TEXT
457 11:
458         movq    -64(%esi),%mm0
459         movq    -56(%esi),%mm1
460         movq    -48(%esi),%mm2
461         movq    -40(%esi),%mm3
462         movq    -32(%esi),%mm4
463         movq    -24(%esi),%mm5
464         movq    -16(%esi),%mm6
465         movq    -8(%esi),%mm7
466         /*prefetchnta -128(%esi)*/
467         subl    $64,%esi
468         movq    %mm0,-64(%edi)
469         movq    %mm1,-56(%edi)
470         movq    %mm2,-48(%edi)
471         movq    %mm3,-40(%edi)
472         movq    %mm4,-32(%edi)
473         movq    %mm5,-24(%edi)
474         movq    %mm6,-16(%edi)
475         movq    %mm7,-8(%edi)
476         subl    $64,%edi
477 12:
478         subl    $64,%ecx
479         jae     11b
480         addl    $64,%ecx
481         jz      13f
482         decl    %esi
483         decl    %edi
484         std
485         rep
486         movsb
487         cld
488 13:
489         MMX_RESTORE_BLOCK
490         ret
491