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