Create a normal stack frame in generic_bcopy() to aid debugging, so
[dragonfly.git] / sys / i386 / i386 / support.s
1 /*-
2  * Copyright (c) 1993 The Regents of the University of California.
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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/sys/i386/i386/support.s,v 1.67.2.5 2001/08/15 01:23:50 peter Exp $
34  * $DragonFly: src/sys/i386/i386/Attic/support.s,v 1.10 2004/04/03 08:21:16 dillon Exp $
35  */
36
37 #include "use_npx.h"
38
39 #include <machine/asmacros.h>
40 #include <machine/cputypes.h>
41 #include <machine/pmap.h>
42 #include <machine/specialreg.h>
43
44 #include "assym.s"
45
46 #define IDXSHIFT        10
47
48         .data
49         .globl  bcopy_vector
50 bcopy_vector:
51         .long   generic_bcopy
52         .globl  bzero
53 bzero:
54         .long   generic_bzero
55         .globl  copyin_vector
56 copyin_vector:
57         .long   generic_copyin
58         .globl  copyout_vector
59 copyout_vector:
60         .long   generic_copyout
61         .globl  ovbcopy_vector
62 ovbcopy_vector:
63         .long   generic_bcopy
64 #if defined(I586_CPU) && NNPX > 0
65 kernel_fpu_lock:
66         .byte   0xfe
67         .space  3
68 #endif
69
70         .text
71
72 /*
73  * bcopy family
74  * void bzero(void *buf, u_int len)
75  */
76
77 ENTRY(generic_bzero)
78         pushl   %edi
79         movl    8(%esp),%edi
80         movl    12(%esp),%ecx
81         xorl    %eax,%eax
82         shrl    $2,%ecx
83         cld
84         rep
85         stosl
86         movl    12(%esp),%ecx
87         andl    $3,%ecx
88         rep
89         stosb
90         popl    %edi
91         ret
92
93 #if defined(I486_CPU)
94 ENTRY(i486_bzero)
95         movl    4(%esp),%edx
96         movl    8(%esp),%ecx
97         xorl    %eax,%eax
98 /*
99  * do 64 byte chunks first
100  *
101  * XXX this is probably over-unrolled at least for DX2's
102  */
103 2:
104         cmpl    $64,%ecx
105         jb      3f
106         movl    %eax,(%edx)
107         movl    %eax,4(%edx)
108         movl    %eax,8(%edx)
109         movl    %eax,12(%edx)
110         movl    %eax,16(%edx)
111         movl    %eax,20(%edx)
112         movl    %eax,24(%edx)
113         movl    %eax,28(%edx)
114         movl    %eax,32(%edx)
115         movl    %eax,36(%edx)
116         movl    %eax,40(%edx)
117         movl    %eax,44(%edx)
118         movl    %eax,48(%edx)
119         movl    %eax,52(%edx)
120         movl    %eax,56(%edx)
121         movl    %eax,60(%edx)
122         addl    $64,%edx
123         subl    $64,%ecx
124         jnz     2b
125         ret
126
127 /*
128  * do 16 byte chunks
129  */
130         SUPERALIGN_TEXT
131 3:
132         cmpl    $16,%ecx
133         jb      4f
134         movl    %eax,(%edx)
135         movl    %eax,4(%edx)
136         movl    %eax,8(%edx)
137         movl    %eax,12(%edx)
138         addl    $16,%edx
139         subl    $16,%ecx
140         jnz     3b
141         ret
142
143 /*
144  * do 4 byte chunks
145  */
146         SUPERALIGN_TEXT
147 4:
148         cmpl    $4,%ecx
149         jb      5f
150         movl    %eax,(%edx)
151         addl    $4,%edx
152         subl    $4,%ecx
153         jnz     4b
154         ret
155
156 /*
157  * do 1 byte chunks
158  * a jump table seems to be faster than a loop or more range reductions
159  *
160  * XXX need a const section for non-text
161  */
162         .data
163 jtab:
164         .long   do0
165         .long   do1
166         .long   do2
167         .long   do3
168
169         .text
170         SUPERALIGN_TEXT
171 5:
172         jmp     *jtab(,%ecx,4)
173
174         SUPERALIGN_TEXT
175 do3:
176         movw    %ax,(%edx)
177         movb    %al,2(%edx)
178         ret
179
180         SUPERALIGN_TEXT
181 do2:
182         movw    %ax,(%edx)
183         ret
184
185         SUPERALIGN_TEXT
186 do1:
187         movb    %al,(%edx)
188         ret
189
190         SUPERALIGN_TEXT
191 do0:
192         ret
193 #endif
194
195 #if defined(I586_CPU) && NNPX > 0
196 ENTRY(i586_bzero)
197         movl    4(%esp),%edx
198         movl    8(%esp),%ecx
199
200         /*
201          * The FPU register method is twice as fast as the integer register
202          * method unless the target is in the L1 cache and we pre-allocate a
203          * cache line for it (then the integer register method is 4-5 times
204          * faster).  However, we never pre-allocate cache lines, since that
205          * would make the integer method 25% or more slower for the common
206          * case when the target isn't in either the L1 cache or the L2 cache.
207          * Thus we normally use the FPU register method unless the overhead
208          * would be too large.
209          */
210         cmpl    $256,%ecx       /* empirical; clts, fninit, smsw cost a lot */
211         jb      intreg_i586_bzero
212
213         /*
214          * The FPU registers may belong to an application or to fastmove()
215          * or to another invocation of bcopy() or ourself in a higher level
216          * interrupt or trap handler.  Preserving the registers is
217          * complicated since we avoid it if possible at all levels.  We
218          * want to localize the complications even when that increases them.
219          * Here the extra work involves preserving CR0_TS in TS.
220          * `npxthread != NULL' is supposed to be the condition that all the
221          * FPU resources belong to an application, but npxthread and CR0_TS
222          * aren't set atomically enough for this condition to work in
223          * interrupt handlers.
224          *
225          * Case 1: FPU registers belong to the application: we must preserve
226          * the registers if we use them, so we only use the FPU register
227          * method if the target size is large enough to amortize the extra
228          * overhead for preserving them.  CR0_TS must be preserved although
229          * it is very likely to end up as set.
230          *
231          * Case 2: FPU registers belong to fastmove(): fastmove() currently
232          * makes the registers look like they belong to an application so
233          * that cpu_switch() and savectx() don't have to know about it, so
234          * this case reduces to case 1.
235          *
236          * Case 3: FPU registers belong to the kernel: don't use the FPU
237          * register method.  This case is unlikely, and supporting it would
238          * be more complicated and might take too much stack.
239          *
240          * Case 4: FPU registers don't belong to anyone: the FPU registers
241          * don't need to be preserved, so we always use the FPU register
242          * method.  CR0_TS must be preserved although it is very likely to
243          * always end up as clear.
244          */
245         cmpl    $0,PCPU(npxthread)
246         je      i586_bz1
247         cmpl    $256+184,%ecx           /* empirical; not quite 2*108 more */
248         jb      intreg_i586_bzero
249         sarb    $1,kernel_fpu_lock
250         jc      intreg_i586_bzero
251         smsw    %ax
252         clts
253         subl    $108,%esp
254         fnsave  0(%esp)
255         jmp     i586_bz2
256
257 i586_bz1:
258         sarb    $1,kernel_fpu_lock
259         jc      intreg_i586_bzero
260         smsw    %ax
261         clts
262         fninit                          /* XXX should avoid needing this */
263 i586_bz2:
264         fldz
265
266         /*
267          * Align to an 8 byte boundary (misalignment in the main loop would
268          * cost a factor of >= 2).  Avoid jumps (at little cost if it is
269          * already aligned) by always zeroing 8 bytes and using the part up
270          * to the _next_ alignment position.
271          */
272         fstl    0(%edx)
273         addl    %edx,%ecx               /* part of %ecx -= new_%edx - %edx */
274         addl    $8,%edx
275         andl    $~7,%edx
276         subl    %edx,%ecx
277
278         /*
279          * Similarly align `len' to a multiple of 8.
280          */
281         fstl    -8(%edx,%ecx)
282         decl    %ecx
283         andl    $~7,%ecx
284
285         /*
286          * This wouldn't be any faster if it were unrolled, since the loop
287          * control instructions are much faster than the fstl and/or done
288          * in parallel with it so their overhead is insignificant.
289          */
290 fpureg_i586_bzero_loop:
291         fstl    0(%edx)
292         addl    $8,%edx
293         subl    $8,%ecx
294         cmpl    $8,%ecx
295         jae     fpureg_i586_bzero_loop
296
297         cmpl    $0,PCPU(npxthread)
298         je      i586_bz3
299         frstor  0(%esp)
300         addl    $108,%esp
301         lmsw    %ax
302         movb    $0xfe,kernel_fpu_lock
303         ret
304
305 i586_bz3:
306         fstp    %st(0)
307         lmsw    %ax
308         movb    $0xfe,kernel_fpu_lock
309         ret
310
311 intreg_i586_bzero:
312         /*
313          * `rep stos' seems to be the best method in practice for small
314          * counts.  Fancy methods usually take too long to start up due
315          * to cache and BTB misses.
316          */
317         pushl   %edi
318         movl    %edx,%edi
319         xorl    %eax,%eax
320         shrl    $2,%ecx
321         cld
322         rep
323         stosl
324         movl    12(%esp),%ecx
325         andl    $3,%ecx
326         jne     1f
327         popl    %edi
328         ret
329
330 1:
331         rep
332         stosb
333         popl    %edi
334         ret
335 #endif /* I586_CPU && NNPX > 0 */
336
337 ENTRY(i686_pagezero)
338         pushl   %edi
339         pushl   %ebx
340
341         movl    12(%esp), %edi
342         movl    $1024, %ecx
343         cld
344
345         ALIGN_TEXT
346 1:
347         xorl    %eax, %eax
348         repe
349         scasl   
350         jnz     2f
351
352         popl    %ebx
353         popl    %edi
354         ret
355
356         ALIGN_TEXT
357
358 2:
359         incl    %ecx
360         subl    $4, %edi
361
362         movl    %ecx, %edx
363         cmpl    $16, %ecx
364
365         jge     3f
366
367         movl    %edi, %ebx
368         andl    $0x3f, %ebx
369         shrl    %ebx
370         shrl    %ebx
371         movl    $16, %ecx
372         subl    %ebx, %ecx
373
374 3:
375         subl    %ecx, %edx
376         rep
377         stosl
378
379         movl    %edx, %ecx
380         testl   %edx, %edx
381         jnz     1b
382
383         popl    %ebx
384         popl    %edi
385         ret
386
387 /* fillw(pat, base, cnt) */
388 ENTRY(fillw)
389         pushl   %edi
390         movl    8(%esp),%eax
391         movl    12(%esp),%edi
392         movl    16(%esp),%ecx
393         cld
394         rep
395         stosw
396         popl    %edi
397         ret
398
399 ENTRY(bcopyb)
400         pushl   %esi
401         pushl   %edi
402         movl    12(%esp),%esi
403         movl    16(%esp),%edi
404         movl    20(%esp),%ecx
405         movl    %edi,%eax
406         subl    %esi,%eax
407         cmpl    %ecx,%eax                       /* overlapping && src < dst? */
408         jb      1f
409         cld                                     /* nope, copy forwards */
410         rep
411         movsb
412         popl    %edi
413         popl    %esi
414         ret
415
416         ALIGN_TEXT
417 1:
418         addl    %ecx,%edi                       /* copy backwards. */
419         addl    %ecx,%esi
420         decl    %edi
421         decl    %esi
422         std
423         rep
424         movsb
425         popl    %edi
426         popl    %esi
427         cld
428         ret
429
430 ENTRY(bcopy)
431         MEXITCOUNT
432         jmp     *bcopy_vector
433
434 ENTRY(ovbcopy)
435         MEXITCOUNT
436         jmp     *ovbcopy_vector
437
438 /*
439  * generic_bcopy(src, dst, cnt)
440  *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
441  */
442 ENTRY(generic_bcopy)
443         pushl   %ebp                            /* debugging */
444         movl    %esp,%ebp
445         pushl   %esi
446         pushl   %edi
447         movl    16(%esp),%esi
448         movl    20(%esp),%edi
449         movl    24(%esp),%ecx
450
451         movl    %edi,%eax
452         subl    %esi,%eax
453         cmpl    %ecx,%eax                       /* overlapping && src < dst? */
454         jb      1f
455
456         shrl    $2,%ecx                         /* copy by 32-bit words */
457         cld                                     /* nope, copy forwards */
458         rep
459         movsl
460         movl    24(%esp),%ecx
461         andl    $3,%ecx                         /* any bytes left? */
462         rep
463         movsb
464         popl    %edi
465         popl    %esi
466         popl    %ebp
467         ret
468
469         ALIGN_TEXT
470 1:
471         addl    %ecx,%edi                       /* copy backwards */
472         addl    %ecx,%esi
473         decl    %edi
474         decl    %esi
475         andl    $3,%ecx                         /* any fractional bytes? */
476         std
477         rep
478         movsb
479         movl    24(%esp),%ecx                   /* copy remainder by 32-bit words */
480         shrl    $2,%ecx
481         subl    $3,%esi
482         subl    $3,%edi
483         rep
484         movsl
485         popl    %edi
486         popl    %esi
487         popl    %ebp
488         cld
489         ret
490
491 #if defined(I586_CPU) && NNPX > 0
492 ENTRY(i586_bcopy)
493         pushl   %esi
494         pushl   %edi
495         movl    12(%esp),%esi
496         movl    16(%esp),%edi
497         movl    20(%esp),%ecx
498
499         movl    %edi,%eax
500         subl    %esi,%eax
501         cmpl    %ecx,%eax                       /* overlapping && src < dst? */
502         jb      1f
503
504         cmpl    $1024,%ecx
505         jb      small_i586_bcopy
506
507         sarb    $1,kernel_fpu_lock
508         jc      small_i586_bcopy
509         cmpl    $0,PCPU(npxthread)
510         je      i586_bc1
511         smsw    %dx
512         clts
513         subl    $108,%esp
514         fnsave  0(%esp)
515         jmp     4f
516
517 i586_bc1:
518         smsw    %dx
519         clts
520         fninit                          /* XXX should avoid needing this */
521
522         ALIGN_TEXT
523 4:
524         pushl   %ecx
525 #define DCACHE_SIZE     8192
526         cmpl    $(DCACHE_SIZE-512)/2,%ecx
527         jbe     2f
528         movl    $(DCACHE_SIZE-512)/2,%ecx
529 2:
530         subl    %ecx,0(%esp)
531         cmpl    $256,%ecx
532         jb      5f                      /* XXX should prefetch if %ecx >= 32 */
533         pushl   %esi
534         pushl   %ecx
535         ALIGN_TEXT
536 3:
537         movl    0(%esi),%eax
538         movl    32(%esi),%eax
539         movl    64(%esi),%eax
540         movl    96(%esi),%eax
541         movl    128(%esi),%eax
542         movl    160(%esi),%eax
543         movl    192(%esi),%eax
544         movl    224(%esi),%eax
545         addl    $256,%esi
546         subl    $256,%ecx
547         cmpl    $256,%ecx
548         jae     3b
549         popl    %ecx
550         popl    %esi
551 5:
552         ALIGN_TEXT
553 large_i586_bcopy_loop:
554         fildq   0(%esi)
555         fildq   8(%esi)
556         fildq   16(%esi)
557         fildq   24(%esi)
558         fildq   32(%esi)
559         fildq   40(%esi)
560         fildq   48(%esi)
561         fildq   56(%esi)
562         fistpq  56(%edi)
563         fistpq  48(%edi)
564         fistpq  40(%edi)
565         fistpq  32(%edi)
566         fistpq  24(%edi)
567         fistpq  16(%edi)
568         fistpq  8(%edi)
569         fistpq  0(%edi)
570         addl    $64,%esi
571         addl    $64,%edi
572         subl    $64,%ecx
573         cmpl    $64,%ecx
574         jae     large_i586_bcopy_loop
575         popl    %eax
576         addl    %eax,%ecx
577         cmpl    $64,%ecx
578         jae     4b
579
580         cmpl    $0,PCPU(npxthread)
581         je      i586_bc2
582         frstor  0(%esp)
583         addl    $108,%esp
584 i586_bc2:
585         lmsw    %dx
586         movb    $0xfe,kernel_fpu_lock
587
588 /*
589  * This is a duplicate of the main part of generic_bcopy.  See the comments
590  * there.  Jumping into generic_bcopy would cost a whole 0-1 cycles and
591  * would mess up high resolution profiling.
592  */
593         ALIGN_TEXT
594 small_i586_bcopy:
595         shrl    $2,%ecx
596         cld
597         rep
598         movsl
599         movl    20(%esp),%ecx
600         andl    $3,%ecx
601         rep
602         movsb
603         popl    %edi
604         popl    %esi
605         ret
606
607         ALIGN_TEXT
608 1:
609         addl    %ecx,%edi
610         addl    %ecx,%esi
611         decl    %edi
612         decl    %esi
613         andl    $3,%ecx
614         std
615         rep
616         movsb
617         movl    20(%esp),%ecx
618         shrl    $2,%ecx
619         subl    $3,%esi
620         subl    $3,%edi
621         rep
622         movsl
623         popl    %edi
624         popl    %esi
625         cld
626         ret
627 #endif /* I586_CPU && NNPX > 0 */
628
629 /*
630  * Note: memcpy does not support overlapping copies
631  */
632 ENTRY(memcpy)
633         pushl   %edi
634         pushl   %esi
635         movl    12(%esp),%edi
636         movl    16(%esp),%esi
637         movl    20(%esp),%ecx
638         movl    %edi,%eax
639         shrl    $2,%ecx                         /* copy by 32-bit words */
640         cld                                     /* nope, copy forwards */
641         rep
642         movsl
643         movl    20(%esp),%ecx
644         andl    $3,%ecx                         /* any bytes left? */
645         rep
646         movsb
647         popl    %esi
648         popl    %edi
649         ret
650
651
652 /*****************************************************************************/
653 /* copyout and fubyte family                                                 */
654 /*****************************************************************************/
655 /*
656  * Access user memory from inside the kernel. These routines and possibly
657  * the math- and DOS emulators should be the only places that do this.
658  *
659  * We have to access the memory with user's permissions, so use a segment
660  * selector with RPL 3. For writes to user space we have to additionally
661  * check the PTE for write permission, because the 386 does not check
662  * write permissions when we are executing with EPL 0. The 486 does check
663  * this if the WP bit is set in CR0, so we can use a simpler version here.
664  *
665  * These routines set curpcb->onfault for the time they execute. When a
666  * protection violation occurs inside the functions, the trap handler
667  * returns to *curpcb->onfault instead of the function.
668  */
669
670 /*
671  * copyout(from_kernel, to_user, len)  - MP SAFE (if not I386_CPU)
672  */
673 ENTRY(copyout)
674         MEXITCOUNT
675         jmp     *copyout_vector
676
677 ENTRY(generic_copyout)
678         movl    PCPU(curthread),%eax
679         movl    TD_PCB(%eax),%eax
680         movl    $copyout_fault,PCB_ONFAULT(%eax)
681         pushl   %esi
682         pushl   %edi
683         pushl   %ebx
684         movl    16(%esp),%esi
685         movl    20(%esp),%edi
686         movl    24(%esp),%ebx
687         testl   %ebx,%ebx                       /* anything to do? */
688         jz      done_copyout
689
690         /*
691          * Check explicitly for non-user addresses.  If 486 write protection
692          * is being used, this check is essential because we are in kernel
693          * mode so the h/w does not provide any protection against writing
694          * kernel addresses.
695          */
696
697         /*
698          * First, prevent address wrapping.
699          */
700         movl    %edi,%eax
701         addl    %ebx,%eax
702         jc      copyout_fault
703 /*
704  * XXX STOP USING VM_MAXUSER_ADDRESS.
705  * It is an end address, not a max, so every time it is used correctly it
706  * looks like there is an off by one error, and of course it caused an off
707  * by one error in several places.
708  */
709         cmpl    $VM_MAXUSER_ADDRESS,%eax
710         ja      copyout_fault
711
712 #if defined(I386_CPU)
713
714 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
715         cmpl    $CPUCLASS_386,cpu_class
716         jne     3f
717 #endif
718 /*
719  * We have to check each PTE for user write permission.
720  * The checking may cause a page fault, so it is important to set
721  * up everything for return via copyout_fault before here.
722  */
723         /* compute number of pages */
724         movl    %edi,%ecx
725         andl    $PAGE_MASK,%ecx
726         addl    %ebx,%ecx
727         decl    %ecx
728         shrl    $IDXSHIFT+2,%ecx
729         incl    %ecx
730
731         /* compute PTE offset for start address */
732         movl    %edi,%edx
733         shrl    $IDXSHIFT,%edx
734         andb    $0xfc,%dl
735
736 1:
737         /* check PTE for each page */
738         leal    PTmap(%edx),%eax
739         shrl    $IDXSHIFT,%eax
740         andb    $0xfc,%al
741         testb   $PG_V,PTmap(%eax)               /* PTE page must be valid */
742         je      4f
743         movb    PTmap(%edx),%al
744         andb    $PG_V|PG_RW|PG_U,%al            /* page must be valid and user writable */
745         cmpb    $PG_V|PG_RW|PG_U,%al
746         je      2f
747
748 4:
749         /* simulate a trap */
750         pushl   %edx
751         pushl   %ecx
752         shll    $IDXSHIFT,%edx
753         pushl   %edx
754         call    trapwrite                       /* trapwrite(addr) */
755         popl    %edx
756         popl    %ecx
757         popl    %edx
758
759         testl   %eax,%eax                       /* if not ok, return EFAULT */
760         jnz     copyout_fault
761
762 2:
763         addl    $4,%edx
764         decl    %ecx
765         jnz     1b                              /* check next page */
766 #endif /* I386_CPU */
767
768         /* bcopy(%esi, %edi, %ebx) */
769 3:
770         movl    %ebx,%ecx
771
772 #if defined(I586_CPU) && NNPX > 0
773         ALIGN_TEXT
774 slow_copyout:
775 #endif
776         shrl    $2,%ecx
777         cld
778         rep
779         movsl
780         movb    %bl,%cl
781         andb    $3,%cl
782         rep
783         movsb
784
785 done_copyout:
786         popl    %ebx
787         popl    %edi
788         popl    %esi
789         xorl    %eax,%eax
790         movl    PCPU(curthread),%edx
791         movl    TD_PCB(%edx),%edx
792         movl    %eax,PCB_ONFAULT(%edx)
793         ret
794
795         ALIGN_TEXT
796 copyout_fault:
797         popl    %ebx
798         popl    %edi
799         popl    %esi
800         movl    PCPU(curthread),%edx
801         movl    TD_PCB(%edx),%edx
802         movl    $0,PCB_ONFAULT(%edx)
803         movl    $EFAULT,%eax
804         ret
805
806 #if defined(I586_CPU) && NNPX > 0
807 ENTRY(i586_copyout)
808         /*
809          * Duplicated from generic_copyout.  Could be done a bit better.
810          */
811         movl    PCPU(curthread),%eax
812         movl    TD_PCB(%eax),%eax
813         movl    $copyout_fault,PCB_ONFAULT(%eax)
814         pushl   %esi
815         pushl   %edi
816         pushl   %ebx
817         movl    16(%esp),%esi
818         movl    20(%esp),%edi
819         movl    24(%esp),%ebx
820         testl   %ebx,%ebx                       /* anything to do? */
821         jz      done_copyout
822
823         /*
824          * Check explicitly for non-user addresses.  If 486 write protection
825          * is being used, this check is essential because we are in kernel
826          * mode so the h/w does not provide any protection against writing
827          * kernel addresses.
828          */
829
830         /*
831          * First, prevent address wrapping.
832          */
833         movl    %edi,%eax
834         addl    %ebx,%eax
835         jc      copyout_fault
836 /*
837  * XXX STOP USING VM_MAXUSER_ADDRESS.
838  * It is an end address, not a max, so every time it is used correctly it
839  * looks like there is an off by one error, and of course it caused an off
840  * by one error in several places.
841  */
842         cmpl    $VM_MAXUSER_ADDRESS,%eax
843         ja      copyout_fault
844
845         /* bcopy(%esi, %edi, %ebx) */
846 3:
847         movl    %ebx,%ecx
848         /*
849          * End of duplicated code.
850          */
851
852         cmpl    $1024,%ecx
853         jb      slow_copyout
854
855         pushl   %ecx
856         call    fastmove
857         addl    $4,%esp
858         jmp     done_copyout
859 #endif /* I586_CPU && NNPX > 0 */
860
861 /*
862  * copyin(from_user, to_kernel, len) - MP SAFE
863  */
864 ENTRY(copyin)
865         MEXITCOUNT
866         jmp     *copyin_vector
867
868 ENTRY(generic_copyin)
869         movl    PCPU(curthread),%eax
870         movl    TD_PCB(%eax),%eax
871         movl    $copyin_fault,PCB_ONFAULT(%eax)
872         pushl   %esi
873         pushl   %edi
874         movl    12(%esp),%esi                   /* caddr_t from */
875         movl    16(%esp),%edi                   /* caddr_t to */
876         movl    20(%esp),%ecx                   /* size_t  len */
877
878         /*
879          * make sure address is valid
880          */
881         movl    %esi,%edx
882         addl    %ecx,%edx
883         jc      copyin_fault
884         cmpl    $VM_MAXUSER_ADDRESS,%edx
885         ja      copyin_fault
886
887 #if defined(I586_CPU) && NNPX > 0
888         ALIGN_TEXT
889 slow_copyin:
890 #endif
891         movb    %cl,%al
892         shrl    $2,%ecx                         /* copy longword-wise */
893         cld
894         rep
895         movsl
896         movb    %al,%cl
897         andb    $3,%cl                          /* copy remaining bytes */
898         rep
899         movsb
900
901 #if defined(I586_CPU) && NNPX > 0
902         ALIGN_TEXT
903 done_copyin:
904 #endif
905         popl    %edi
906         popl    %esi
907         xorl    %eax,%eax
908         movl    PCPU(curthread),%edx
909         movl    TD_PCB(%edx),%edx
910         movl    %eax,PCB_ONFAULT(%edx)
911         ret
912
913         ALIGN_TEXT
914 copyin_fault:
915         popl    %edi
916         popl    %esi
917         movl    PCPU(curthread),%edx
918         movl    TD_PCB(%edx),%edx
919         movl    $0,PCB_ONFAULT(%edx)
920         movl    $EFAULT,%eax
921         ret
922
923 #if defined(I586_CPU) && NNPX > 0
924 ENTRY(i586_copyin)
925         /*
926          * Duplicated from generic_copyin.  Could be done a bit better.
927          */
928         movl    PCPU(curthread),%eax
929         movl    TD_PCB(%eax),%eax
930         movl    $copyin_fault,PCB_ONFAULT(%eax)
931         pushl   %esi
932         pushl   %edi
933         movl    12(%esp),%esi                   /* caddr_t from */
934         movl    16(%esp),%edi                   /* caddr_t to */
935         movl    20(%esp),%ecx                   /* size_t  len */
936
937         /*
938          * make sure address is valid
939          */
940         movl    %esi,%edx
941         addl    %ecx,%edx
942         jc      copyin_fault
943         cmpl    $VM_MAXUSER_ADDRESS,%edx
944         ja      copyin_fault
945         /*
946          * End of duplicated code.
947          */
948
949         cmpl    $1024,%ecx
950         jb      slow_copyin
951
952         pushl   %ebx                    /* XXX prepare for fastmove_fault */
953         pushl   %ecx
954         call    fastmove
955         addl    $8,%esp
956         jmp     done_copyin
957 #endif /* I586_CPU && NNPX > 0 */
958
959 #if defined(I586_CPU) && NNPX > 0
960 /* fastmove(src, dst, len)
961         src in %esi
962         dst in %edi
963         len in %ecx             XXX changed to on stack for profiling
964         uses %eax and %edx for tmp. storage
965  */
966 /* XXX use ENTRY() to get profiling.  fastmove() is actually a non-entry. */
967 ENTRY(fastmove)
968         pushl   %ebp
969         movl    %esp,%ebp
970         subl    $PCB_SAVE87_SIZE+3*4,%esp
971
972         movl    8(%ebp),%ecx
973         cmpl    $63,%ecx
974         jbe     fastmove_tail
975
976         testl   $7,%esi /* check if src addr is multiple of 8 */
977         jnz     fastmove_tail
978
979         testl   $7,%edi /* check if dst addr is multiple of 8 */
980         jnz     fastmove_tail
981
982 /* if (npxthread != NULL) { */
983         cmpl    $0,PCPU(npxthread)
984         je      6f
985 /*    fnsave(&curpcb->pcb_savefpu); */
986         movl    PCPU(curthread),%eax
987         movl    TD_PCB(%eax),%eax
988         fnsave  PCB_SAVEFPU(%eax)
989 /*   npxthread = NULL; */
990         movl    $0,PCPU(npxthread)
991 /* } */
992 6:
993 /* now we own the FPU. */
994
995 /*
996  * The process' FP state is saved in the pcb, but if we get
997  * switched, the cpu_switch() will store our FP state in the
998  * pcb.  It should be possible to avoid all the copying for
999  * this, e.g., by setting a flag to tell cpu_switch() to
1000  * save the state somewhere else.
1001  */
1002 /* tmp = curpcb->pcb_savefpu; */
1003         movl    %ecx,-12(%ebp)
1004         movl    %esi,-8(%ebp)
1005         movl    %edi,-4(%ebp)
1006         movl    %esp,%edi
1007         movl    PCPU(curthread),%esi
1008         movl    TD_PCB(%esi),%esi
1009         addl    $PCB_SAVEFPU,%esi
1010         cld
1011         movl    $PCB_SAVE87_SIZE>>2,%ecx
1012         rep
1013         movsl
1014         movl    -12(%ebp),%ecx
1015         movl    -8(%ebp),%esi
1016         movl    -4(%ebp),%edi
1017 /* stop_emulating(); */
1018         clts
1019 /* npxthread = curthread; */
1020         movl    PCPU(curthread),%eax
1021         movl    %eax,PCPU(npxthread)
1022         movl    PCPU(curthread),%eax
1023         movl    TD_PCB(%eax),%eax
1024         movl    $fastmove_fault,PCB_ONFAULT(%eax)
1025 4:
1026         movl    %ecx,-12(%ebp)
1027         cmpl    $1792,%ecx
1028         jbe     2f
1029         movl    $1792,%ecx
1030 2:
1031         subl    %ecx,-12(%ebp)
1032         cmpl    $256,%ecx
1033         jb      5f
1034         movl    %ecx,-8(%ebp)
1035         movl    %esi,-4(%ebp)
1036         ALIGN_TEXT
1037 3:
1038         movl    0(%esi),%eax
1039         movl    32(%esi),%eax
1040         movl    64(%esi),%eax
1041         movl    96(%esi),%eax
1042         movl    128(%esi),%eax
1043         movl    160(%esi),%eax
1044         movl    192(%esi),%eax
1045         movl    224(%esi),%eax
1046         addl    $256,%esi
1047         subl    $256,%ecx
1048         cmpl    $256,%ecx
1049         jae     3b
1050         movl    -8(%ebp),%ecx
1051         movl    -4(%ebp),%esi
1052 5:
1053         ALIGN_TEXT
1054 fastmove_loop:
1055         fildq   0(%esi)
1056         fildq   8(%esi)
1057         fildq   16(%esi)
1058         fildq   24(%esi)
1059         fildq   32(%esi)
1060         fildq   40(%esi)
1061         fildq   48(%esi)
1062         fildq   56(%esi)
1063         fistpq  56(%edi)
1064         fistpq  48(%edi)
1065         fistpq  40(%edi)
1066         fistpq  32(%edi)
1067         fistpq  24(%edi)
1068         fistpq  16(%edi)
1069         fistpq  8(%edi)
1070         fistpq  0(%edi)
1071         addl    $-64,%ecx
1072         addl    $64,%esi
1073         addl    $64,%edi
1074         cmpl    $63,%ecx
1075         ja      fastmove_loop
1076         movl    -12(%ebp),%eax
1077         addl    %eax,%ecx
1078         cmpl    $64,%ecx
1079         jae     4b
1080
1081 /* curpcb->pcb_savefpu = tmp; */
1082         movl    %ecx,-12(%ebp)
1083         movl    %esi,-8(%ebp)
1084         movl    %edi,-4(%ebp)
1085         movl    PCPU(curthread),%edi
1086         movl    TD_PCB(%edi),%edi
1087         addl    $PCB_SAVEFPU,%edi
1088         movl    %esp,%esi
1089         cld
1090         movl    $PCB_SAVE87_SIZE>>2,%ecx
1091         rep
1092         movsl
1093         movl    -12(%ebp),%ecx
1094         movl    -8(%ebp),%esi
1095         movl    -4(%ebp),%edi
1096
1097 /* start_emulating(); */
1098         smsw    %ax
1099         orb     $CR0_TS,%al
1100         lmsw    %ax
1101 /* npxthread = NULL; */
1102         movl    $0,PCPU(npxthread)
1103
1104         ALIGN_TEXT
1105 fastmove_tail:
1106         movl    PCPU(curthread),%eax
1107         movl    TD_PCB(%eax),%eax
1108         movl    $fastmove_tail_fault,PCB_ONFAULT(%eax)
1109
1110         movb    %cl,%al
1111         shrl    $2,%ecx                         /* copy longword-wise */
1112         cld
1113         rep
1114         movsl
1115         movb    %al,%cl
1116         andb    $3,%cl                          /* copy remaining bytes */
1117         rep
1118         movsb
1119
1120         movl    %ebp,%esp
1121         popl    %ebp
1122         ret
1123
1124         ALIGN_TEXT
1125 fastmove_fault:
1126         movl    PCPU(curthread),%edi
1127         movl    TD_PCB(%edi),%edi
1128         addl    $PCB_SAVEFPU,%edi
1129         movl    %esp,%esi
1130         cld
1131         movl    $PCB_SAVE87_SIZE>>2,%ecx
1132         rep
1133         movsl
1134
1135         smsw    %ax
1136         orb     $CR0_TS,%al
1137         lmsw    %ax
1138         movl    $0,PCPU(npxthread)
1139
1140 fastmove_tail_fault:
1141         movl    %ebp,%esp
1142         popl    %ebp
1143         addl    $8,%esp
1144         popl    %ebx
1145         popl    %edi
1146         popl    %esi
1147         movl    PCPU(curthread),%edx
1148         movl    TD_PCB(%edx),%edx
1149         movl    $0,PCB_ONFAULT(%edx)
1150         movl    $EFAULT,%eax
1151         ret
1152 #endif /* I586_CPU && NNPX > 0 */
1153
1154 /*
1155  * fu{byte,sword,word} - MP SAFE
1156  *
1157  *      Fetch a byte (sword, word) from user memory
1158  */
1159 ENTRY(fuword)
1160         movl    PCPU(curthread),%ecx
1161         movl    TD_PCB(%ecx),%ecx
1162         movl    $fusufault,PCB_ONFAULT(%ecx)
1163         movl    4(%esp),%edx                    /* from */
1164
1165         cmpl    $VM_MAXUSER_ADDRESS-4,%edx      /* verify address is valid */
1166         ja      fusufault
1167
1168         movl    (%edx),%eax
1169         movl    $0,PCB_ONFAULT(%ecx)
1170         ret
1171
1172 /*
1173  * These two routines are called from the profiling code, potentially
1174  * at interrupt time. If they fail, that's okay, good things will
1175  * happen later. Fail all the time for now - until the trap code is
1176  * able to deal with this.
1177  */
1178 ALTENTRY(suswintr)
1179 ENTRY(fuswintr)
1180         movl    $-1,%eax
1181         ret
1182
1183 /*
1184  * fusword - MP SAFE
1185  */
1186 ENTRY(fusword)
1187         movl    PCPU(curthread),%ecx
1188         movl    TD_PCB(%ecx),%ecx
1189         movl    $fusufault,PCB_ONFAULT(%ecx)
1190         movl    4(%esp),%edx
1191
1192         cmpl    $VM_MAXUSER_ADDRESS-2,%edx
1193         ja      fusufault
1194
1195         movzwl  (%edx),%eax
1196         movl    $0,PCB_ONFAULT(%ecx)
1197         ret
1198
1199 /*
1200  * fubyte - MP SAFE
1201  */
1202 ENTRY(fubyte)
1203         movl    PCPU(curthread),%ecx
1204         movl    TD_PCB(%ecx),%ecx
1205         movl    $fusufault,PCB_ONFAULT(%ecx)
1206         movl    4(%esp),%edx
1207
1208         cmpl    $VM_MAXUSER_ADDRESS-1,%edx
1209         ja      fusufault
1210
1211         movzbl  (%edx),%eax
1212         movl    $0,PCB_ONFAULT(%ecx)
1213         ret
1214
1215         ALIGN_TEXT
1216 fusufault:
1217         movl    PCPU(curthread),%ecx
1218         movl    TD_PCB(%ecx),%ecx
1219         xorl    %eax,%eax
1220         movl    %eax,PCB_ONFAULT(%ecx)
1221         decl    %eax
1222         ret
1223
1224 /*
1225  * su{byte,sword,word} - MP SAFE (if not I386_CPU)
1226  *
1227  *      Write a byte (word, longword) to user memory
1228  */
1229 ENTRY(suword)
1230         movl    PCPU(curthread),%ecx
1231         movl    TD_PCB(%ecx),%ecx
1232         movl    $fusufault,PCB_ONFAULT(%ecx)
1233         movl    4(%esp),%edx
1234
1235 #if defined(I386_CPU)
1236
1237 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1238         cmpl    $CPUCLASS_386,cpu_class
1239         jne     2f                              /* we only have to set the right segment selector */
1240 #endif /* I486_CPU || I586_CPU || I686_CPU */
1241
1242         /* XXX - page boundary crossing is still not handled */
1243         movl    %edx,%eax
1244         shrl    $IDXSHIFT,%edx
1245         andb    $0xfc,%dl
1246
1247         leal    PTmap(%edx),%ecx
1248         shrl    $IDXSHIFT,%ecx
1249         andb    $0xfc,%cl
1250         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
1251         je      4f
1252         movb    PTmap(%edx),%dl
1253         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
1254         cmpb    $PG_V|PG_RW|PG_U,%dl
1255         je      1f
1256
1257 4:
1258         /* simulate a trap */
1259         pushl   %eax
1260         call    trapwrite
1261         popl    %edx                            /* remove junk parameter from stack */
1262         testl   %eax,%eax
1263         jnz     fusufault
1264 1:
1265         movl    4(%esp),%edx
1266 #endif
1267
1268 2:
1269         cmpl    $VM_MAXUSER_ADDRESS-4,%edx      /* verify address validity */
1270         ja      fusufault
1271
1272         movl    8(%esp),%eax
1273         movl    %eax,(%edx)
1274         xorl    %eax,%eax
1275         movl    PCPU(curthread),%ecx
1276         movl    TD_PCB(%ecx),%ecx
1277         movl    %eax,PCB_ONFAULT(%ecx)
1278         ret
1279
1280 /*
1281  * susword - MP SAFE (if not I386_CPU)
1282  */
1283 ENTRY(susword)
1284         movl    PCPU(curthread),%ecx
1285         movl    TD_PCB(%ecx),%ecx
1286         movl    $fusufault,PCB_ONFAULT(%ecx)
1287         movl    4(%esp),%edx
1288
1289 #if defined(I386_CPU)
1290
1291 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1292         cmpl    $CPUCLASS_386,cpu_class
1293         jne     2f
1294 #endif /* I486_CPU || I586_CPU || I686_CPU */
1295
1296         /* XXX - page boundary crossing is still not handled */
1297         movl    %edx,%eax
1298         shrl    $IDXSHIFT,%edx
1299         andb    $0xfc,%dl
1300
1301         leal    PTmap(%edx),%ecx
1302         shrl    $IDXSHIFT,%ecx
1303         andb    $0xfc,%cl
1304         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
1305         je      4f
1306         movb    PTmap(%edx),%dl
1307         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
1308         cmpb    $PG_V|PG_RW|PG_U,%dl
1309         je      1f
1310
1311 4:
1312         /* simulate a trap */
1313         pushl   %eax
1314         call    trapwrite
1315         popl    %edx                            /* remove junk parameter from stack */
1316         testl   %eax,%eax
1317         jnz     fusufault
1318 1:
1319         movl    4(%esp),%edx
1320 #endif
1321
1322 2:
1323         cmpl    $VM_MAXUSER_ADDRESS-2,%edx      /* verify address validity */
1324         ja      fusufault
1325
1326         movw    8(%esp),%ax
1327         movw    %ax,(%edx)
1328         xorl    %eax,%eax
1329         movl    PCPU(curthread),%ecx                    /* restore trashed register */
1330         movl    TD_PCB(%ecx),%ecx
1331         movl    %eax,PCB_ONFAULT(%ecx)
1332         ret
1333
1334 /*
1335  * su[i]byte - MP SAFE (if not I386_CPU)
1336  */
1337 ALTENTRY(suibyte)
1338 ENTRY(subyte)
1339         movl    PCPU(curthread),%ecx
1340         movl    TD_PCB(%ecx),%ecx
1341         movl    $fusufault,PCB_ONFAULT(%ecx)
1342         movl    4(%esp),%edx
1343
1344 #if defined(I386_CPU)
1345
1346 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1347         cmpl    $CPUCLASS_386,cpu_class
1348         jne     2f
1349 #endif /* I486_CPU || I586_CPU || I686_CPU */
1350
1351         movl    %edx,%eax
1352         shrl    $IDXSHIFT,%edx
1353         andb    $0xfc,%dl
1354
1355         leal    PTmap(%edx),%ecx
1356         shrl    $IDXSHIFT,%ecx
1357         andb    $0xfc,%cl
1358         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
1359         je      4f
1360         movb    PTmap(%edx),%dl
1361         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
1362         cmpb    $PG_V|PG_RW|PG_U,%dl
1363         je      1f
1364
1365 4:
1366         /* simulate a trap */
1367         pushl   %eax
1368         call    trapwrite
1369         popl    %edx                            /* remove junk parameter from stack */
1370         testl   %eax,%eax
1371         jnz     fusufault
1372 1:
1373         movl    4(%esp),%edx
1374 #endif
1375
1376 2:
1377         cmpl    $VM_MAXUSER_ADDRESS-1,%edx      /* verify address validity */
1378         ja      fusufault
1379
1380         movb    8(%esp),%al
1381         movb    %al,(%edx)
1382         xorl    %eax,%eax
1383         movl    PCPU(curthread),%ecx            /* restore trashed register */
1384         movl    TD_PCB(%ecx),%ecx
1385         movl    %eax,PCB_ONFAULT(%ecx)
1386         ret
1387
1388 /*
1389  * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
1390  *
1391  *      copy a string from from to to, stop when a 0 character is reached.
1392  *      return ENAMETOOLONG if string is longer than maxlen, and
1393  *      EFAULT on protection violations. If lencopied is non-zero,
1394  *      return the actual length in *lencopied.
1395  */
1396 ENTRY(copyinstr)
1397         pushl   %esi
1398         pushl   %edi
1399         movl    PCPU(curthread),%ecx
1400         movl    TD_PCB(%ecx),%ecx
1401         movl    $cpystrflt,PCB_ONFAULT(%ecx)
1402
1403         movl    12(%esp),%esi                   /* %esi = from */
1404         movl    16(%esp),%edi                   /* %edi = to */
1405         movl    20(%esp),%edx                   /* %edx = maxlen */
1406
1407         movl    $VM_MAXUSER_ADDRESS,%eax
1408
1409         /* make sure 'from' is within bounds */
1410         subl    %esi,%eax
1411         jbe     cpystrflt
1412
1413         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1414         cmpl    %edx,%eax
1415         jae     1f
1416         movl    %eax,%edx
1417         movl    %eax,20(%esp)
1418 1:
1419         incl    %edx
1420         cld
1421
1422 2:
1423         decl    %edx
1424         jz      3f
1425
1426         lodsb
1427         stosb
1428         orb     %al,%al
1429         jnz     2b
1430
1431         /* Success -- 0 byte reached */
1432         decl    %edx
1433         xorl    %eax,%eax
1434         jmp     cpystrflt_x
1435 3:
1436         /* edx is zero - return ENAMETOOLONG or EFAULT */
1437         cmpl    $VM_MAXUSER_ADDRESS,%esi
1438         jae     cpystrflt
1439 4:
1440         movl    $ENAMETOOLONG,%eax
1441         jmp     cpystrflt_x
1442
1443 cpystrflt:
1444         movl    $EFAULT,%eax
1445
1446 cpystrflt_x:
1447         /* set *lencopied and return %eax */
1448         movl    PCPU(curthread),%ecx
1449         movl    TD_PCB(%ecx),%ecx
1450         movl    $0,PCB_ONFAULT(%ecx)
1451         movl    20(%esp),%ecx
1452         subl    %edx,%ecx
1453         movl    24(%esp),%edx
1454         testl   %edx,%edx
1455         jz      1f
1456         movl    %ecx,(%edx)
1457 1:
1458         popl    %edi
1459         popl    %esi
1460         ret
1461
1462
1463 /*
1464  * copystr(from, to, maxlen, int *lencopied) - MP SAFE
1465  */
1466 ENTRY(copystr)
1467         pushl   %esi
1468         pushl   %edi
1469
1470         movl    12(%esp),%esi                   /* %esi = from */
1471         movl    16(%esp),%edi                   /* %edi = to */
1472         movl    20(%esp),%edx                   /* %edx = maxlen */
1473         incl    %edx
1474         cld
1475 1:
1476         decl    %edx
1477         jz      4f
1478         lodsb
1479         stosb
1480         orb     %al,%al
1481         jnz     1b
1482
1483         /* Success -- 0 byte reached */
1484         decl    %edx
1485         xorl    %eax,%eax
1486         jmp     6f
1487 4:
1488         /* edx is zero -- return ENAMETOOLONG */
1489         movl    $ENAMETOOLONG,%eax
1490
1491 6:
1492         /* set *lencopied and return %eax */
1493         movl    20(%esp),%ecx
1494         subl    %edx,%ecx
1495         movl    24(%esp),%edx
1496         testl   %edx,%edx
1497         jz      7f
1498         movl    %ecx,(%edx)
1499 7:
1500         popl    %edi
1501         popl    %esi
1502         ret
1503
1504 ENTRY(bcmp)
1505         pushl   %edi
1506         pushl   %esi
1507         movl    12(%esp),%edi
1508         movl    16(%esp),%esi
1509         movl    20(%esp),%edx
1510         xorl    %eax,%eax
1511
1512         movl    %edx,%ecx
1513         shrl    $2,%ecx
1514         cld                                     /* compare forwards */
1515         repe
1516         cmpsl
1517         jne     1f
1518
1519         movl    %edx,%ecx
1520         andl    $3,%ecx
1521         repe
1522         cmpsb
1523         je      2f
1524 1:
1525         incl    %eax
1526 2:
1527         popl    %esi
1528         popl    %edi
1529         ret
1530
1531
1532 /*
1533  * Handling of special 386 registers and descriptor tables etc
1534  */
1535 /* void lgdt(struct region_descriptor *rdp); */
1536 ENTRY(lgdt)
1537         /* reload the descriptor table */
1538         movl    4(%esp),%eax
1539         lgdt    (%eax)
1540
1541         /* flush the prefetch q */
1542         jmp     1f
1543         nop
1544 1:
1545         /* reload "stale" selectors */
1546         movl    $KDSEL,%eax
1547         mov     %ax,%ds
1548         mov     %ax,%es
1549         mov     %ax,%gs
1550         mov     %ax,%ss
1551         movl    $KPSEL,%eax
1552         mov     %ax,%fs
1553
1554         /* reload code selector by turning return into intersegmental return */
1555         movl    (%esp),%eax
1556         pushl   %eax
1557         movl    $KCSEL,4(%esp)
1558         lret
1559
1560 /*
1561  * void lidt(struct region_descriptor *rdp);
1562  */
1563 ENTRY(lidt)
1564         movl    4(%esp),%eax
1565         lidt    (%eax)
1566         ret
1567
1568 /*
1569  * void lldt(u_short sel)
1570  */
1571 ENTRY(lldt)
1572         lldt    4(%esp)
1573         ret
1574
1575 /*
1576  * void ltr(u_short sel)
1577  */
1578 ENTRY(ltr)
1579         ltr     4(%esp)
1580         ret
1581
1582 /* ssdtosd(*ssdp,*sdp) */
1583 ENTRY(ssdtosd)
1584         pushl   %ebx
1585         movl    8(%esp),%ecx
1586         movl    8(%ecx),%ebx
1587         shll    $16,%ebx
1588         movl    (%ecx),%edx
1589         roll    $16,%edx
1590         movb    %dh,%bl
1591         movb    %dl,%bh
1592         rorl    $8,%ebx
1593         movl    4(%ecx),%eax
1594         movw    %ax,%dx
1595         andl    $0xf0000,%eax
1596         orl     %eax,%ebx
1597         movl    12(%esp),%ecx
1598         movl    %edx,(%ecx)
1599         movl    %ebx,4(%ecx)
1600         popl    %ebx
1601         ret
1602
1603 /* load_cr0(cr0) */
1604 ENTRY(load_cr0)
1605         movl    4(%esp),%eax
1606         movl    %eax,%cr0
1607         ret
1608
1609 /* rcr0() */
1610 ENTRY(rcr0)
1611         movl    %cr0,%eax
1612         ret
1613
1614 /* rcr3() */
1615 ENTRY(rcr3)
1616         movl    %cr3,%eax
1617         ret
1618
1619 /* void load_cr3(caddr_t cr3) */
1620 ENTRY(load_cr3)
1621 #if defined(SWTCH_OPTIM_STATS)
1622         incl    _tlb_flush_count
1623 #endif
1624         movl    4(%esp),%eax
1625         movl    %eax,%cr3
1626         ret
1627
1628 /* rcr4() */
1629 ENTRY(rcr4)
1630         movl    %cr4,%eax
1631         ret
1632
1633 /* void load_cr4(caddr_t cr4) */
1634 ENTRY(load_cr4)
1635         movl    4(%esp),%eax
1636         movl    %eax,%cr4
1637         ret
1638
1639 /* void reset_dbregs() */
1640 ENTRY(reset_dbregs)
1641         movl    $0,%eax
1642         movl    %eax,%dr7     /* disable all breapoints first */
1643         movl    %eax,%dr0
1644         movl    %eax,%dr1
1645         movl    %eax,%dr2
1646         movl    %eax,%dr3
1647         movl    %eax,%dr6
1648         ret
1649
1650 /*****************************************************************************/
1651 /* setjump, longjump                                                         */
1652 /*****************************************************************************/
1653
1654 ENTRY(setjmp)
1655         movl    4(%esp),%eax
1656         movl    %ebx,(%eax)                     /* save ebx */
1657         movl    %esp,4(%eax)                    /* save esp */
1658         movl    %ebp,8(%eax)                    /* save ebp */
1659         movl    %esi,12(%eax)                   /* save esi */
1660         movl    %edi,16(%eax)                   /* save edi */
1661         movl    (%esp),%edx                     /* get rta */
1662         movl    %edx,20(%eax)                   /* save eip */
1663         xorl    %eax,%eax                       /* return(0); */
1664         ret
1665
1666 ENTRY(longjmp)
1667         movl    4(%esp),%eax
1668         movl    (%eax),%ebx                     /* restore ebx */
1669         movl    4(%eax),%esp                    /* restore esp */
1670         movl    8(%eax),%ebp                    /* restore ebp */
1671         movl    12(%eax),%esi                   /* restore esi */
1672         movl    16(%eax),%edi                   /* restore edi */
1673         movl    20(%eax),%edx                   /* get rta */
1674         movl    %edx,(%esp)                     /* put in return frame */
1675         xorl    %eax,%eax                       /* return(1); */
1676         incl    %eax
1677         ret
1678
1679 /*
1680  * Support for BB-profiling (gcc -a).  The kernbb program will extract
1681  * the data from the kernel.
1682  */
1683
1684         .data
1685         ALIGN_DATA
1686         .globl bbhead
1687 bbhead:
1688         .long 0
1689
1690         .text
1691 NON_GPROF_ENTRY(__bb_init_func)
1692         movl    4(%esp),%eax
1693         movl    $1,(%eax)
1694         movl    bbhead,%edx
1695         movl    %edx,16(%eax)
1696         movl    %eax,bbhead
1697         .byte   0xc3                            /* avoid macro for `ret' */