49400953492f390dfd19583e65050bd1a22d271f
[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.9 2003/08/07 21:17:22 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   %esi
444         pushl   %edi
445         movl    12(%esp),%esi
446         movl    16(%esp),%edi
447         movl    20(%esp),%ecx
448
449         movl    %edi,%eax
450         subl    %esi,%eax
451         cmpl    %ecx,%eax                       /* overlapping && src < dst? */
452         jb      1f
453
454         shrl    $2,%ecx                         /* copy by 32-bit words */
455         cld                                     /* nope, copy forwards */
456         rep
457         movsl
458         movl    20(%esp),%ecx
459         andl    $3,%ecx                         /* any bytes left? */
460         rep
461         movsb
462         popl    %edi
463         popl    %esi
464         ret
465
466         ALIGN_TEXT
467 1:
468         addl    %ecx,%edi                       /* copy backwards */
469         addl    %ecx,%esi
470         decl    %edi
471         decl    %esi
472         andl    $3,%ecx                         /* any fractional bytes? */
473         std
474         rep
475         movsb
476         movl    20(%esp),%ecx                   /* copy remainder by 32-bit words */
477         shrl    $2,%ecx
478         subl    $3,%esi
479         subl    $3,%edi
480         rep
481         movsl
482         popl    %edi
483         popl    %esi
484         cld
485         ret
486
487 #if defined(I586_CPU) && NNPX > 0
488 ENTRY(i586_bcopy)
489         pushl   %esi
490         pushl   %edi
491         movl    12(%esp),%esi
492         movl    16(%esp),%edi
493         movl    20(%esp),%ecx
494
495         movl    %edi,%eax
496         subl    %esi,%eax
497         cmpl    %ecx,%eax                       /* overlapping && src < dst? */
498         jb      1f
499
500         cmpl    $1024,%ecx
501         jb      small_i586_bcopy
502
503         sarb    $1,kernel_fpu_lock
504         jc      small_i586_bcopy
505         cmpl    $0,PCPU(npxthread)
506         je      i586_bc1
507         smsw    %dx
508         clts
509         subl    $108,%esp
510         fnsave  0(%esp)
511         jmp     4f
512
513 i586_bc1:
514         smsw    %dx
515         clts
516         fninit                          /* XXX should avoid needing this */
517
518         ALIGN_TEXT
519 4:
520         pushl   %ecx
521 #define DCACHE_SIZE     8192
522         cmpl    $(DCACHE_SIZE-512)/2,%ecx
523         jbe     2f
524         movl    $(DCACHE_SIZE-512)/2,%ecx
525 2:
526         subl    %ecx,0(%esp)
527         cmpl    $256,%ecx
528         jb      5f                      /* XXX should prefetch if %ecx >= 32 */
529         pushl   %esi
530         pushl   %ecx
531         ALIGN_TEXT
532 3:
533         movl    0(%esi),%eax
534         movl    32(%esi),%eax
535         movl    64(%esi),%eax
536         movl    96(%esi),%eax
537         movl    128(%esi),%eax
538         movl    160(%esi),%eax
539         movl    192(%esi),%eax
540         movl    224(%esi),%eax
541         addl    $256,%esi
542         subl    $256,%ecx
543         cmpl    $256,%ecx
544         jae     3b
545         popl    %ecx
546         popl    %esi
547 5:
548         ALIGN_TEXT
549 large_i586_bcopy_loop:
550         fildq   0(%esi)
551         fildq   8(%esi)
552         fildq   16(%esi)
553         fildq   24(%esi)
554         fildq   32(%esi)
555         fildq   40(%esi)
556         fildq   48(%esi)
557         fildq   56(%esi)
558         fistpq  56(%edi)
559         fistpq  48(%edi)
560         fistpq  40(%edi)
561         fistpq  32(%edi)
562         fistpq  24(%edi)
563         fistpq  16(%edi)
564         fistpq  8(%edi)
565         fistpq  0(%edi)
566         addl    $64,%esi
567         addl    $64,%edi
568         subl    $64,%ecx
569         cmpl    $64,%ecx
570         jae     large_i586_bcopy_loop
571         popl    %eax
572         addl    %eax,%ecx
573         cmpl    $64,%ecx
574         jae     4b
575
576         cmpl    $0,PCPU(npxthread)
577         je      i586_bc2
578         frstor  0(%esp)
579         addl    $108,%esp
580 i586_bc2:
581         lmsw    %dx
582         movb    $0xfe,kernel_fpu_lock
583
584 /*
585  * This is a duplicate of the main part of generic_bcopy.  See the comments
586  * there.  Jumping into generic_bcopy would cost a whole 0-1 cycles and
587  * would mess up high resolution profiling.
588  */
589         ALIGN_TEXT
590 small_i586_bcopy:
591         shrl    $2,%ecx
592         cld
593         rep
594         movsl
595         movl    20(%esp),%ecx
596         andl    $3,%ecx
597         rep
598         movsb
599         popl    %edi
600         popl    %esi
601         ret
602
603         ALIGN_TEXT
604 1:
605         addl    %ecx,%edi
606         addl    %ecx,%esi
607         decl    %edi
608         decl    %esi
609         andl    $3,%ecx
610         std
611         rep
612         movsb
613         movl    20(%esp),%ecx
614         shrl    $2,%ecx
615         subl    $3,%esi
616         subl    $3,%edi
617         rep
618         movsl
619         popl    %edi
620         popl    %esi
621         cld
622         ret
623 #endif /* I586_CPU && NNPX > 0 */
624
625 /*
626  * Note: memcpy does not support overlapping copies
627  */
628 ENTRY(memcpy)
629         pushl   %edi
630         pushl   %esi
631         movl    12(%esp),%edi
632         movl    16(%esp),%esi
633         movl    20(%esp),%ecx
634         movl    %edi,%eax
635         shrl    $2,%ecx                         /* copy by 32-bit words */
636         cld                                     /* nope, copy forwards */
637         rep
638         movsl
639         movl    20(%esp),%ecx
640         andl    $3,%ecx                         /* any bytes left? */
641         rep
642         movsb
643         popl    %esi
644         popl    %edi
645         ret
646
647
648 /*****************************************************************************/
649 /* copyout and fubyte family                                                 */
650 /*****************************************************************************/
651 /*
652  * Access user memory from inside the kernel. These routines and possibly
653  * the math- and DOS emulators should be the only places that do this.
654  *
655  * We have to access the memory with user's permissions, so use a segment
656  * selector with RPL 3. For writes to user space we have to additionally
657  * check the PTE for write permission, because the 386 does not check
658  * write permissions when we are executing with EPL 0. The 486 does check
659  * this if the WP bit is set in CR0, so we can use a simpler version here.
660  *
661  * These routines set curpcb->onfault for the time they execute. When a
662  * protection violation occurs inside the functions, the trap handler
663  * returns to *curpcb->onfault instead of the function.
664  */
665
666 /*
667  * copyout(from_kernel, to_user, len)  - MP SAFE (if not I386_CPU)
668  */
669 ENTRY(copyout)
670         MEXITCOUNT
671         jmp     *copyout_vector
672
673 ENTRY(generic_copyout)
674         movl    PCPU(curthread),%eax
675         movl    TD_PCB(%eax),%eax
676         movl    $copyout_fault,PCB_ONFAULT(%eax)
677         pushl   %esi
678         pushl   %edi
679         pushl   %ebx
680         movl    16(%esp),%esi
681         movl    20(%esp),%edi
682         movl    24(%esp),%ebx
683         testl   %ebx,%ebx                       /* anything to do? */
684         jz      done_copyout
685
686         /*
687          * Check explicitly for non-user addresses.  If 486 write protection
688          * is being used, this check is essential because we are in kernel
689          * mode so the h/w does not provide any protection against writing
690          * kernel addresses.
691          */
692
693         /*
694          * First, prevent address wrapping.
695          */
696         movl    %edi,%eax
697         addl    %ebx,%eax
698         jc      copyout_fault
699 /*
700  * XXX STOP USING VM_MAXUSER_ADDRESS.
701  * It is an end address, not a max, so every time it is used correctly it
702  * looks like there is an off by one error, and of course it caused an off
703  * by one error in several places.
704  */
705         cmpl    $VM_MAXUSER_ADDRESS,%eax
706         ja      copyout_fault
707
708 #if defined(I386_CPU)
709
710 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
711         cmpl    $CPUCLASS_386,cpu_class
712         jne     3f
713 #endif
714 /*
715  * We have to check each PTE for user write permission.
716  * The checking may cause a page fault, so it is important to set
717  * up everything for return via copyout_fault before here.
718  */
719         /* compute number of pages */
720         movl    %edi,%ecx
721         andl    $PAGE_MASK,%ecx
722         addl    %ebx,%ecx
723         decl    %ecx
724         shrl    $IDXSHIFT+2,%ecx
725         incl    %ecx
726
727         /* compute PTE offset for start address */
728         movl    %edi,%edx
729         shrl    $IDXSHIFT,%edx
730         andb    $0xfc,%dl
731
732 1:
733         /* check PTE for each page */
734         leal    PTmap(%edx),%eax
735         shrl    $IDXSHIFT,%eax
736         andb    $0xfc,%al
737         testb   $PG_V,PTmap(%eax)               /* PTE page must be valid */
738         je      4f
739         movb    PTmap(%edx),%al
740         andb    $PG_V|PG_RW|PG_U,%al            /* page must be valid and user writable */
741         cmpb    $PG_V|PG_RW|PG_U,%al
742         je      2f
743
744 4:
745         /* simulate a trap */
746         pushl   %edx
747         pushl   %ecx
748         shll    $IDXSHIFT,%edx
749         pushl   %edx
750         call    trapwrite                       /* trapwrite(addr) */
751         popl    %edx
752         popl    %ecx
753         popl    %edx
754
755         testl   %eax,%eax                       /* if not ok, return EFAULT */
756         jnz     copyout_fault
757
758 2:
759         addl    $4,%edx
760         decl    %ecx
761         jnz     1b                              /* check next page */
762 #endif /* I386_CPU */
763
764         /* bcopy(%esi, %edi, %ebx) */
765 3:
766         movl    %ebx,%ecx
767
768 #if defined(I586_CPU) && NNPX > 0
769         ALIGN_TEXT
770 slow_copyout:
771 #endif
772         shrl    $2,%ecx
773         cld
774         rep
775         movsl
776         movb    %bl,%cl
777         andb    $3,%cl
778         rep
779         movsb
780
781 done_copyout:
782         popl    %ebx
783         popl    %edi
784         popl    %esi
785         xorl    %eax,%eax
786         movl    PCPU(curthread),%edx
787         movl    TD_PCB(%edx),%edx
788         movl    %eax,PCB_ONFAULT(%edx)
789         ret
790
791         ALIGN_TEXT
792 copyout_fault:
793         popl    %ebx
794         popl    %edi
795         popl    %esi
796         movl    PCPU(curthread),%edx
797         movl    TD_PCB(%edx),%edx
798         movl    $0,PCB_ONFAULT(%edx)
799         movl    $EFAULT,%eax
800         ret
801
802 #if defined(I586_CPU) && NNPX > 0
803 ENTRY(i586_copyout)
804         /*
805          * Duplicated from generic_copyout.  Could be done a bit better.
806          */
807         movl    PCPU(curthread),%eax
808         movl    TD_PCB(%eax),%eax
809         movl    $copyout_fault,PCB_ONFAULT(%eax)
810         pushl   %esi
811         pushl   %edi
812         pushl   %ebx
813         movl    16(%esp),%esi
814         movl    20(%esp),%edi
815         movl    24(%esp),%ebx
816         testl   %ebx,%ebx                       /* anything to do? */
817         jz      done_copyout
818
819         /*
820          * Check explicitly for non-user addresses.  If 486 write protection
821          * is being used, this check is essential because we are in kernel
822          * mode so the h/w does not provide any protection against writing
823          * kernel addresses.
824          */
825
826         /*
827          * First, prevent address wrapping.
828          */
829         movl    %edi,%eax
830         addl    %ebx,%eax
831         jc      copyout_fault
832 /*
833  * XXX STOP USING VM_MAXUSER_ADDRESS.
834  * It is an end address, not a max, so every time it is used correctly it
835  * looks like there is an off by one error, and of course it caused an off
836  * by one error in several places.
837  */
838         cmpl    $VM_MAXUSER_ADDRESS,%eax
839         ja      copyout_fault
840
841         /* bcopy(%esi, %edi, %ebx) */
842 3:
843         movl    %ebx,%ecx
844         /*
845          * End of duplicated code.
846          */
847
848         cmpl    $1024,%ecx
849         jb      slow_copyout
850
851         pushl   %ecx
852         call    fastmove
853         addl    $4,%esp
854         jmp     done_copyout
855 #endif /* I586_CPU && NNPX > 0 */
856
857 /*
858  * copyin(from_user, to_kernel, len) - MP SAFE
859  */
860 ENTRY(copyin)
861         MEXITCOUNT
862         jmp     *copyin_vector
863
864 ENTRY(generic_copyin)
865         movl    PCPU(curthread),%eax
866         movl    TD_PCB(%eax),%eax
867         movl    $copyin_fault,PCB_ONFAULT(%eax)
868         pushl   %esi
869         pushl   %edi
870         movl    12(%esp),%esi                   /* caddr_t from */
871         movl    16(%esp),%edi                   /* caddr_t to */
872         movl    20(%esp),%ecx                   /* size_t  len */
873
874         /*
875          * make sure address is valid
876          */
877         movl    %esi,%edx
878         addl    %ecx,%edx
879         jc      copyin_fault
880         cmpl    $VM_MAXUSER_ADDRESS,%edx
881         ja      copyin_fault
882
883 #if defined(I586_CPU) && NNPX > 0
884         ALIGN_TEXT
885 slow_copyin:
886 #endif
887         movb    %cl,%al
888         shrl    $2,%ecx                         /* copy longword-wise */
889         cld
890         rep
891         movsl
892         movb    %al,%cl
893         andb    $3,%cl                          /* copy remaining bytes */
894         rep
895         movsb
896
897 #if defined(I586_CPU) && NNPX > 0
898         ALIGN_TEXT
899 done_copyin:
900 #endif
901         popl    %edi
902         popl    %esi
903         xorl    %eax,%eax
904         movl    PCPU(curthread),%edx
905         movl    TD_PCB(%edx),%edx
906         movl    %eax,PCB_ONFAULT(%edx)
907         ret
908
909         ALIGN_TEXT
910 copyin_fault:
911         popl    %edi
912         popl    %esi
913         movl    PCPU(curthread),%edx
914         movl    TD_PCB(%edx),%edx
915         movl    $0,PCB_ONFAULT(%edx)
916         movl    $EFAULT,%eax
917         ret
918
919 #if defined(I586_CPU) && NNPX > 0
920 ENTRY(i586_copyin)
921         /*
922          * Duplicated from generic_copyin.  Could be done a bit better.
923          */
924         movl    PCPU(curthread),%eax
925         movl    TD_PCB(%eax),%eax
926         movl    $copyin_fault,PCB_ONFAULT(%eax)
927         pushl   %esi
928         pushl   %edi
929         movl    12(%esp),%esi                   /* caddr_t from */
930         movl    16(%esp),%edi                   /* caddr_t to */
931         movl    20(%esp),%ecx                   /* size_t  len */
932
933         /*
934          * make sure address is valid
935          */
936         movl    %esi,%edx
937         addl    %ecx,%edx
938         jc      copyin_fault
939         cmpl    $VM_MAXUSER_ADDRESS,%edx
940         ja      copyin_fault
941         /*
942          * End of duplicated code.
943          */
944
945         cmpl    $1024,%ecx
946         jb      slow_copyin
947
948         pushl   %ebx                    /* XXX prepare for fastmove_fault */
949         pushl   %ecx
950         call    fastmove
951         addl    $8,%esp
952         jmp     done_copyin
953 #endif /* I586_CPU && NNPX > 0 */
954
955 #if defined(I586_CPU) && NNPX > 0
956 /* fastmove(src, dst, len)
957         src in %esi
958         dst in %edi
959         len in %ecx             XXX changed to on stack for profiling
960         uses %eax and %edx for tmp. storage
961  */
962 /* XXX use ENTRY() to get profiling.  fastmove() is actually a non-entry. */
963 ENTRY(fastmove)
964         pushl   %ebp
965         movl    %esp,%ebp
966         subl    $PCB_SAVE87_SIZE+3*4,%esp
967
968         movl    8(%ebp),%ecx
969         cmpl    $63,%ecx
970         jbe     fastmove_tail
971
972         testl   $7,%esi /* check if src addr is multiple of 8 */
973         jnz     fastmove_tail
974
975         testl   $7,%edi /* check if dst addr is multiple of 8 */
976         jnz     fastmove_tail
977
978 /* if (npxthread != NULL) { */
979         cmpl    $0,PCPU(npxthread)
980         je      6f
981 /*    fnsave(&curpcb->pcb_savefpu); */
982         movl    PCPU(curthread),%eax
983         movl    TD_PCB(%eax),%eax
984         fnsave  PCB_SAVEFPU(%eax)
985 /*   npxthread = NULL; */
986         movl    $0,PCPU(npxthread)
987 /* } */
988 6:
989 /* now we own the FPU. */
990
991 /*
992  * The process' FP state is saved in the pcb, but if we get
993  * switched, the cpu_switch() will store our FP state in the
994  * pcb.  It should be possible to avoid all the copying for
995  * this, e.g., by setting a flag to tell cpu_switch() to
996  * save the state somewhere else.
997  */
998 /* tmp = curpcb->pcb_savefpu; */
999         movl    %ecx,-12(%ebp)
1000         movl    %esi,-8(%ebp)
1001         movl    %edi,-4(%ebp)
1002         movl    %esp,%edi
1003         movl    PCPU(curthread),%esi
1004         movl    TD_PCB(%esi),%esi
1005         addl    $PCB_SAVEFPU,%esi
1006         cld
1007         movl    $PCB_SAVE87_SIZE>>2,%ecx
1008         rep
1009         movsl
1010         movl    -12(%ebp),%ecx
1011         movl    -8(%ebp),%esi
1012         movl    -4(%ebp),%edi
1013 /* stop_emulating(); */
1014         clts
1015 /* npxthread = curthread; */
1016         movl    PCPU(curthread),%eax
1017         movl    %eax,PCPU(npxthread)
1018         movl    PCPU(curthread),%eax
1019         movl    TD_PCB(%eax),%eax
1020         movl    $fastmove_fault,PCB_ONFAULT(%eax)
1021 4:
1022         movl    %ecx,-12(%ebp)
1023         cmpl    $1792,%ecx
1024         jbe     2f
1025         movl    $1792,%ecx
1026 2:
1027         subl    %ecx,-12(%ebp)
1028         cmpl    $256,%ecx
1029         jb      5f
1030         movl    %ecx,-8(%ebp)
1031         movl    %esi,-4(%ebp)
1032         ALIGN_TEXT
1033 3:
1034         movl    0(%esi),%eax
1035         movl    32(%esi),%eax
1036         movl    64(%esi),%eax
1037         movl    96(%esi),%eax
1038         movl    128(%esi),%eax
1039         movl    160(%esi),%eax
1040         movl    192(%esi),%eax
1041         movl    224(%esi),%eax
1042         addl    $256,%esi
1043         subl    $256,%ecx
1044         cmpl    $256,%ecx
1045         jae     3b
1046         movl    -8(%ebp),%ecx
1047         movl    -4(%ebp),%esi
1048 5:
1049         ALIGN_TEXT
1050 fastmove_loop:
1051         fildq   0(%esi)
1052         fildq   8(%esi)
1053         fildq   16(%esi)
1054         fildq   24(%esi)
1055         fildq   32(%esi)
1056         fildq   40(%esi)
1057         fildq   48(%esi)
1058         fildq   56(%esi)
1059         fistpq  56(%edi)
1060         fistpq  48(%edi)
1061         fistpq  40(%edi)
1062         fistpq  32(%edi)
1063         fistpq  24(%edi)
1064         fistpq  16(%edi)
1065         fistpq  8(%edi)
1066         fistpq  0(%edi)
1067         addl    $-64,%ecx
1068         addl    $64,%esi
1069         addl    $64,%edi
1070         cmpl    $63,%ecx
1071         ja      fastmove_loop
1072         movl    -12(%ebp),%eax
1073         addl    %eax,%ecx
1074         cmpl    $64,%ecx
1075         jae     4b
1076
1077 /* curpcb->pcb_savefpu = tmp; */
1078         movl    %ecx,-12(%ebp)
1079         movl    %esi,-8(%ebp)
1080         movl    %edi,-4(%ebp)
1081         movl    PCPU(curthread),%edi
1082         movl    TD_PCB(%edi),%edi
1083         addl    $PCB_SAVEFPU,%edi
1084         movl    %esp,%esi
1085         cld
1086         movl    $PCB_SAVE87_SIZE>>2,%ecx
1087         rep
1088         movsl
1089         movl    -12(%ebp),%ecx
1090         movl    -8(%ebp),%esi
1091         movl    -4(%ebp),%edi
1092
1093 /* start_emulating(); */
1094         smsw    %ax
1095         orb     $CR0_TS,%al
1096         lmsw    %ax
1097 /* npxthread = NULL; */
1098         movl    $0,PCPU(npxthread)
1099
1100         ALIGN_TEXT
1101 fastmove_tail:
1102         movl    PCPU(curthread),%eax
1103         movl    TD_PCB(%eax),%eax
1104         movl    $fastmove_tail_fault,PCB_ONFAULT(%eax)
1105
1106         movb    %cl,%al
1107         shrl    $2,%ecx                         /* copy longword-wise */
1108         cld
1109         rep
1110         movsl
1111         movb    %al,%cl
1112         andb    $3,%cl                          /* copy remaining bytes */
1113         rep
1114         movsb
1115
1116         movl    %ebp,%esp
1117         popl    %ebp
1118         ret
1119
1120         ALIGN_TEXT
1121 fastmove_fault:
1122         movl    PCPU(curthread),%edi
1123         movl    TD_PCB(%edi),%edi
1124         addl    $PCB_SAVEFPU,%edi
1125         movl    %esp,%esi
1126         cld
1127         movl    $PCB_SAVE87_SIZE>>2,%ecx
1128         rep
1129         movsl
1130
1131         smsw    %ax
1132         orb     $CR0_TS,%al
1133         lmsw    %ax
1134         movl    $0,PCPU(npxthread)
1135
1136 fastmove_tail_fault:
1137         movl    %ebp,%esp
1138         popl    %ebp
1139         addl    $8,%esp
1140         popl    %ebx
1141         popl    %edi
1142         popl    %esi
1143         movl    PCPU(curthread),%edx
1144         movl    TD_PCB(%edx),%edx
1145         movl    $0,PCB_ONFAULT(%edx)
1146         movl    $EFAULT,%eax
1147         ret
1148 #endif /* I586_CPU && NNPX > 0 */
1149
1150 /*
1151  * fu{byte,sword,word} - MP SAFE
1152  *
1153  *      Fetch a byte (sword, word) from user memory
1154  */
1155 ENTRY(fuword)
1156         movl    PCPU(curthread),%ecx
1157         movl    TD_PCB(%ecx),%ecx
1158         movl    $fusufault,PCB_ONFAULT(%ecx)
1159         movl    4(%esp),%edx                    /* from */
1160
1161         cmpl    $VM_MAXUSER_ADDRESS-4,%edx      /* verify address is valid */
1162         ja      fusufault
1163
1164         movl    (%edx),%eax
1165         movl    $0,PCB_ONFAULT(%ecx)
1166         ret
1167
1168 /*
1169  * These two routines are called from the profiling code, potentially
1170  * at interrupt time. If they fail, that's okay, good things will
1171  * happen later. Fail all the time for now - until the trap code is
1172  * able to deal with this.
1173  */
1174 ALTENTRY(suswintr)
1175 ENTRY(fuswintr)
1176         movl    $-1,%eax
1177         ret
1178
1179 /*
1180  * fusword - MP SAFE
1181  */
1182 ENTRY(fusword)
1183         movl    PCPU(curthread),%ecx
1184         movl    TD_PCB(%ecx),%ecx
1185         movl    $fusufault,PCB_ONFAULT(%ecx)
1186         movl    4(%esp),%edx
1187
1188         cmpl    $VM_MAXUSER_ADDRESS-2,%edx
1189         ja      fusufault
1190
1191         movzwl  (%edx),%eax
1192         movl    $0,PCB_ONFAULT(%ecx)
1193         ret
1194
1195 /*
1196  * fubyte - MP SAFE
1197  */
1198 ENTRY(fubyte)
1199         movl    PCPU(curthread),%ecx
1200         movl    TD_PCB(%ecx),%ecx
1201         movl    $fusufault,PCB_ONFAULT(%ecx)
1202         movl    4(%esp),%edx
1203
1204         cmpl    $VM_MAXUSER_ADDRESS-1,%edx
1205         ja      fusufault
1206
1207         movzbl  (%edx),%eax
1208         movl    $0,PCB_ONFAULT(%ecx)
1209         ret
1210
1211         ALIGN_TEXT
1212 fusufault:
1213         movl    PCPU(curthread),%ecx
1214         movl    TD_PCB(%ecx),%ecx
1215         xorl    %eax,%eax
1216         movl    %eax,PCB_ONFAULT(%ecx)
1217         decl    %eax
1218         ret
1219
1220 /*
1221  * su{byte,sword,word} - MP SAFE (if not I386_CPU)
1222  *
1223  *      Write a byte (word, longword) to user memory
1224  */
1225 ENTRY(suword)
1226         movl    PCPU(curthread),%ecx
1227         movl    TD_PCB(%ecx),%ecx
1228         movl    $fusufault,PCB_ONFAULT(%ecx)
1229         movl    4(%esp),%edx
1230
1231 #if defined(I386_CPU)
1232
1233 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1234         cmpl    $CPUCLASS_386,cpu_class
1235         jne     2f                              /* we only have to set the right segment selector */
1236 #endif /* I486_CPU || I586_CPU || I686_CPU */
1237
1238         /* XXX - page boundary crossing is still not handled */
1239         movl    %edx,%eax
1240         shrl    $IDXSHIFT,%edx
1241         andb    $0xfc,%dl
1242
1243         leal    PTmap(%edx),%ecx
1244         shrl    $IDXSHIFT,%ecx
1245         andb    $0xfc,%cl
1246         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
1247         je      4f
1248         movb    PTmap(%edx),%dl
1249         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
1250         cmpb    $PG_V|PG_RW|PG_U,%dl
1251         je      1f
1252
1253 4:
1254         /* simulate a trap */
1255         pushl   %eax
1256         call    trapwrite
1257         popl    %edx                            /* remove junk parameter from stack */
1258         testl   %eax,%eax
1259         jnz     fusufault
1260 1:
1261         movl    4(%esp),%edx
1262 #endif
1263
1264 2:
1265         cmpl    $VM_MAXUSER_ADDRESS-4,%edx      /* verify address validity */
1266         ja      fusufault
1267
1268         movl    8(%esp),%eax
1269         movl    %eax,(%edx)
1270         xorl    %eax,%eax
1271         movl    PCPU(curthread),%ecx
1272         movl    TD_PCB(%ecx),%ecx
1273         movl    %eax,PCB_ONFAULT(%ecx)
1274         ret
1275
1276 /*
1277  * susword - MP SAFE (if not I386_CPU)
1278  */
1279 ENTRY(susword)
1280         movl    PCPU(curthread),%ecx
1281         movl    TD_PCB(%ecx),%ecx
1282         movl    $fusufault,PCB_ONFAULT(%ecx)
1283         movl    4(%esp),%edx
1284
1285 #if defined(I386_CPU)
1286
1287 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1288         cmpl    $CPUCLASS_386,cpu_class
1289         jne     2f
1290 #endif /* I486_CPU || I586_CPU || I686_CPU */
1291
1292         /* XXX - page boundary crossing is still not handled */
1293         movl    %edx,%eax
1294         shrl    $IDXSHIFT,%edx
1295         andb    $0xfc,%dl
1296
1297         leal    PTmap(%edx),%ecx
1298         shrl    $IDXSHIFT,%ecx
1299         andb    $0xfc,%cl
1300         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
1301         je      4f
1302         movb    PTmap(%edx),%dl
1303         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
1304         cmpb    $PG_V|PG_RW|PG_U,%dl
1305         je      1f
1306
1307 4:
1308         /* simulate a trap */
1309         pushl   %eax
1310         call    trapwrite
1311         popl    %edx                            /* remove junk parameter from stack */
1312         testl   %eax,%eax
1313         jnz     fusufault
1314 1:
1315         movl    4(%esp),%edx
1316 #endif
1317
1318 2:
1319         cmpl    $VM_MAXUSER_ADDRESS-2,%edx      /* verify address validity */
1320         ja      fusufault
1321
1322         movw    8(%esp),%ax
1323         movw    %ax,(%edx)
1324         xorl    %eax,%eax
1325         movl    PCPU(curthread),%ecx                    /* restore trashed register */
1326         movl    TD_PCB(%ecx),%ecx
1327         movl    %eax,PCB_ONFAULT(%ecx)
1328         ret
1329
1330 /*
1331  * su[i]byte - MP SAFE (if not I386_CPU)
1332  */
1333 ALTENTRY(suibyte)
1334 ENTRY(subyte)
1335         movl    PCPU(curthread),%ecx
1336         movl    TD_PCB(%ecx),%ecx
1337         movl    $fusufault,PCB_ONFAULT(%ecx)
1338         movl    4(%esp),%edx
1339
1340 #if defined(I386_CPU)
1341
1342 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1343         cmpl    $CPUCLASS_386,cpu_class
1344         jne     2f
1345 #endif /* I486_CPU || I586_CPU || I686_CPU */
1346
1347         movl    %edx,%eax
1348         shrl    $IDXSHIFT,%edx
1349         andb    $0xfc,%dl
1350
1351         leal    PTmap(%edx),%ecx
1352         shrl    $IDXSHIFT,%ecx
1353         andb    $0xfc,%cl
1354         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
1355         je      4f
1356         movb    PTmap(%edx),%dl
1357         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
1358         cmpb    $PG_V|PG_RW|PG_U,%dl
1359         je      1f
1360
1361 4:
1362         /* simulate a trap */
1363         pushl   %eax
1364         call    trapwrite
1365         popl    %edx                            /* remove junk parameter from stack */
1366         testl   %eax,%eax
1367         jnz     fusufault
1368 1:
1369         movl    4(%esp),%edx
1370 #endif
1371
1372 2:
1373         cmpl    $VM_MAXUSER_ADDRESS-1,%edx      /* verify address validity */
1374         ja      fusufault
1375
1376         movb    8(%esp),%al
1377         movb    %al,(%edx)
1378         xorl    %eax,%eax
1379         movl    PCPU(curthread),%ecx            /* restore trashed register */
1380         movl    TD_PCB(%ecx),%ecx
1381         movl    %eax,PCB_ONFAULT(%ecx)
1382         ret
1383
1384 /*
1385  * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
1386  *
1387  *      copy a string from from to to, stop when a 0 character is reached.
1388  *      return ENAMETOOLONG if string is longer than maxlen, and
1389  *      EFAULT on protection violations. If lencopied is non-zero,
1390  *      return the actual length in *lencopied.
1391  */
1392 ENTRY(copyinstr)
1393         pushl   %esi
1394         pushl   %edi
1395         movl    PCPU(curthread),%ecx
1396         movl    TD_PCB(%ecx),%ecx
1397         movl    $cpystrflt,PCB_ONFAULT(%ecx)
1398
1399         movl    12(%esp),%esi                   /* %esi = from */
1400         movl    16(%esp),%edi                   /* %edi = to */
1401         movl    20(%esp),%edx                   /* %edx = maxlen */
1402
1403         movl    $VM_MAXUSER_ADDRESS,%eax
1404
1405         /* make sure 'from' is within bounds */
1406         subl    %esi,%eax
1407         jbe     cpystrflt
1408
1409         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1410         cmpl    %edx,%eax
1411         jae     1f
1412         movl    %eax,%edx
1413         movl    %eax,20(%esp)
1414 1:
1415         incl    %edx
1416         cld
1417
1418 2:
1419         decl    %edx
1420         jz      3f
1421
1422         lodsb
1423         stosb
1424         orb     %al,%al
1425         jnz     2b
1426
1427         /* Success -- 0 byte reached */
1428         decl    %edx
1429         xorl    %eax,%eax
1430         jmp     cpystrflt_x
1431 3:
1432         /* edx is zero - return ENAMETOOLONG or EFAULT */
1433         cmpl    $VM_MAXUSER_ADDRESS,%esi
1434         jae     cpystrflt
1435 4:
1436         movl    $ENAMETOOLONG,%eax
1437         jmp     cpystrflt_x
1438
1439 cpystrflt:
1440         movl    $EFAULT,%eax
1441
1442 cpystrflt_x:
1443         /* set *lencopied and return %eax */
1444         movl    PCPU(curthread),%ecx
1445         movl    TD_PCB(%ecx),%ecx
1446         movl    $0,PCB_ONFAULT(%ecx)
1447         movl    20(%esp),%ecx
1448         subl    %edx,%ecx
1449         movl    24(%esp),%edx
1450         testl   %edx,%edx
1451         jz      1f
1452         movl    %ecx,(%edx)
1453 1:
1454         popl    %edi
1455         popl    %esi
1456         ret
1457
1458
1459 /*
1460  * copystr(from, to, maxlen, int *lencopied) - MP SAFE
1461  */
1462 ENTRY(copystr)
1463         pushl   %esi
1464         pushl   %edi
1465
1466         movl    12(%esp),%esi                   /* %esi = from */
1467         movl    16(%esp),%edi                   /* %edi = to */
1468         movl    20(%esp),%edx                   /* %edx = maxlen */
1469         incl    %edx
1470         cld
1471 1:
1472         decl    %edx
1473         jz      4f
1474         lodsb
1475         stosb
1476         orb     %al,%al
1477         jnz     1b
1478
1479         /* Success -- 0 byte reached */
1480         decl    %edx
1481         xorl    %eax,%eax
1482         jmp     6f
1483 4:
1484         /* edx is zero -- return ENAMETOOLONG */
1485         movl    $ENAMETOOLONG,%eax
1486
1487 6:
1488         /* set *lencopied and return %eax */
1489         movl    20(%esp),%ecx
1490         subl    %edx,%ecx
1491         movl    24(%esp),%edx
1492         testl   %edx,%edx
1493         jz      7f
1494         movl    %ecx,(%edx)
1495 7:
1496         popl    %edi
1497         popl    %esi
1498         ret
1499
1500 ENTRY(bcmp)
1501         pushl   %edi
1502         pushl   %esi
1503         movl    12(%esp),%edi
1504         movl    16(%esp),%esi
1505         movl    20(%esp),%edx
1506         xorl    %eax,%eax
1507
1508         movl    %edx,%ecx
1509         shrl    $2,%ecx
1510         cld                                     /* compare forwards */
1511         repe
1512         cmpsl
1513         jne     1f
1514
1515         movl    %edx,%ecx
1516         andl    $3,%ecx
1517         repe
1518         cmpsb
1519         je      2f
1520 1:
1521         incl    %eax
1522 2:
1523         popl    %esi
1524         popl    %edi
1525         ret
1526
1527
1528 /*
1529  * Handling of special 386 registers and descriptor tables etc
1530  */
1531 /* void lgdt(struct region_descriptor *rdp); */
1532 ENTRY(lgdt)
1533         /* reload the descriptor table */
1534         movl    4(%esp),%eax
1535         lgdt    (%eax)
1536
1537         /* flush the prefetch q */
1538         jmp     1f
1539         nop
1540 1:
1541         /* reload "stale" selectors */
1542         movl    $KDSEL,%eax
1543         mov     %ax,%ds
1544         mov     %ax,%es
1545         mov     %ax,%gs
1546         mov     %ax,%ss
1547         movl    $KPSEL,%eax
1548         mov     %ax,%fs
1549
1550         /* reload code selector by turning return into intersegmental return */
1551         movl    (%esp),%eax
1552         pushl   %eax
1553         movl    $KCSEL,4(%esp)
1554         lret
1555
1556 /*
1557  * void lidt(struct region_descriptor *rdp);
1558  */
1559 ENTRY(lidt)
1560         movl    4(%esp),%eax
1561         lidt    (%eax)
1562         ret
1563
1564 /*
1565  * void lldt(u_short sel)
1566  */
1567 ENTRY(lldt)
1568         lldt    4(%esp)
1569         ret
1570
1571 /*
1572  * void ltr(u_short sel)
1573  */
1574 ENTRY(ltr)
1575         ltr     4(%esp)
1576         ret
1577
1578 /* ssdtosd(*ssdp,*sdp) */
1579 ENTRY(ssdtosd)
1580         pushl   %ebx
1581         movl    8(%esp),%ecx
1582         movl    8(%ecx),%ebx
1583         shll    $16,%ebx
1584         movl    (%ecx),%edx
1585         roll    $16,%edx
1586         movb    %dh,%bl
1587         movb    %dl,%bh
1588         rorl    $8,%ebx
1589         movl    4(%ecx),%eax
1590         movw    %ax,%dx
1591         andl    $0xf0000,%eax
1592         orl     %eax,%ebx
1593         movl    12(%esp),%ecx
1594         movl    %edx,(%ecx)
1595         movl    %ebx,4(%ecx)
1596         popl    %ebx
1597         ret
1598
1599 /* load_cr0(cr0) */
1600 ENTRY(load_cr0)
1601         movl    4(%esp),%eax
1602         movl    %eax,%cr0
1603         ret
1604
1605 /* rcr0() */
1606 ENTRY(rcr0)
1607         movl    %cr0,%eax
1608         ret
1609
1610 /* rcr3() */
1611 ENTRY(rcr3)
1612         movl    %cr3,%eax
1613         ret
1614
1615 /* void load_cr3(caddr_t cr3) */
1616 ENTRY(load_cr3)
1617 #if defined(SWTCH_OPTIM_STATS)
1618         incl    _tlb_flush_count
1619 #endif
1620         movl    4(%esp),%eax
1621         movl    %eax,%cr3
1622         ret
1623
1624 /* rcr4() */
1625 ENTRY(rcr4)
1626         movl    %cr4,%eax
1627         ret
1628
1629 /* void load_cr4(caddr_t cr4) */
1630 ENTRY(load_cr4)
1631         movl    4(%esp),%eax
1632         movl    %eax,%cr4
1633         ret
1634
1635 /* void reset_dbregs() */
1636 ENTRY(reset_dbregs)
1637         movl    $0,%eax
1638         movl    %eax,%dr7     /* disable all breapoints first */
1639         movl    %eax,%dr0
1640         movl    %eax,%dr1
1641         movl    %eax,%dr2
1642         movl    %eax,%dr3
1643         movl    %eax,%dr6
1644         ret
1645
1646 /*****************************************************************************/
1647 /* setjump, longjump                                                         */
1648 /*****************************************************************************/
1649
1650 ENTRY(setjmp)
1651         movl    4(%esp),%eax
1652         movl    %ebx,(%eax)                     /* save ebx */
1653         movl    %esp,4(%eax)                    /* save esp */
1654         movl    %ebp,8(%eax)                    /* save ebp */
1655         movl    %esi,12(%eax)                   /* save esi */
1656         movl    %edi,16(%eax)                   /* save edi */
1657         movl    (%esp),%edx                     /* get rta */
1658         movl    %edx,20(%eax)                   /* save eip */
1659         xorl    %eax,%eax                       /* return(0); */
1660         ret
1661
1662 ENTRY(longjmp)
1663         movl    4(%esp),%eax
1664         movl    (%eax),%ebx                     /* restore ebx */
1665         movl    4(%eax),%esp                    /* restore esp */
1666         movl    8(%eax),%ebp                    /* restore ebp */
1667         movl    12(%eax),%esi                   /* restore esi */
1668         movl    16(%eax),%edi                   /* restore edi */
1669         movl    20(%eax),%edx                   /* get rta */
1670         movl    %edx,(%esp)                     /* put in return frame */
1671         xorl    %eax,%eax                       /* return(1); */
1672         incl    %eax
1673         ret
1674
1675 /*
1676  * Support for BB-profiling (gcc -a).  The kernbb program will extract
1677  * the data from the kernel.
1678  */
1679
1680         .data
1681         ALIGN_DATA
1682         .globl bbhead
1683 bbhead:
1684         .long 0
1685
1686         .text
1687 NON_GPROF_ENTRY(__bb_init_func)
1688         movl    4(%esp),%eax
1689         movl    $1,(%eax)
1690         movl    bbhead,%edx
1691         movl    %edx,16(%eax)
1692         movl    %eax,bbhead
1693         .byte   0xc3                            /* avoid macro for `ret' */