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