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