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