Merge from vendor branch OPENSSL:
[dragonfly.git] / sys / i386 / i386 / support.s
1 /*-
2  * Copyright (c) 1993 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/sys/i386/i386/support.s,v 1.67.2.5 2001/08/15 01:23:50 peter Exp $
34  * $DragonFly: src/sys/i386/i386/Attic/support.s,v 1.12 2004/04/30 09:44:16 dillon Exp $
35  */
36
37 #include "use_npx.h"
38
39 #include <machine/asmacros.h>
40 #include <machine/cputypes.h>
41 #include <machine/pmap.h>
42 #include <machine/specialreg.h>
43
44 #include "assym.s"
45
46 #define IDXSHIFT        10
47
48         .data
49
50         .globl  memcpy_vector
51 memcpy_vector:
52         .long   asm_generic_memcpy
53
54         .globl  bcopy_vector
55 bcopy_vector:
56         .long   asm_generic_bcopy
57
58         .globl  bzero
59 bzero:
60         .long   generic_bzero
61
62         .globl  ovbcopy_vector
63 ovbcopy_vector:
64         .long   asm_generic_bcopy
65
66         .text
67
68 /* fillw(pat, base, cnt) */
69 ENTRY(fillw)
70         pushl   %edi
71         movl    8(%esp),%eax
72         movl    12(%esp),%edi
73         movl    16(%esp),%ecx
74         cld
75         rep
76         stosw
77         popl    %edi
78         ret
79
80 /*
81  * void bcopy(const void *s, void *d, size_t count)
82  *
83  * Normal bcopy() vector, an optimized bcopy may be installed in
84  * bcopy_vector.
85  */
86 ENTRY(bcopy)
87         pushl   %esi
88         pushl   %edi
89         movl    4+8(%esp),%esi                  /* caddr_t from */
90         movl    8+8(%esp),%edi                  /* caddr_t to */
91         movl    12+8(%esp),%ecx                 /* size_t  len */
92         call    *bcopy_vector
93         popl    %edi
94         popl    %esi
95         ret
96
97 /*
98  * Generic (integer-only) bcopy() vector.
99  */
100 ENTRY(generic_bcopy)
101         pushl   %esi
102         pushl   %edi
103         movl    4+8(%esp),%esi                  /* caddr_t from */
104         movl    8+8(%esp),%edi                  /* caddr_t to */
105         movl    12+8(%esp),%ecx                 /* size_t  len */
106         call    asm_generic_bcopy
107         popl    %edi
108         popl    %esi
109         ret
110
111 ENTRY(ovbcopy)
112         pushl   %esi
113         pushl   %edi
114         movl    4+8(%esp),%esi                  /* caddr_t from */
115         movl    8+8(%esp),%edi                  /* caddr_t to */
116         movl    12+8(%esp),%ecx                 /* size_t  len */
117         call    *ovbcopy_vector
118         popl    %edi
119         popl    %esi
120         ret
121
122 /*
123  * void *memcpy(void *d, const void *s, size_t count)
124  *
125  * Note: memcpy does not have to support overlapping copies.
126  *
127  * Note: (d, s) arguments reversed from bcopy, and memcpy() returns d
128  * while bcopy() returns void.
129  */
130 ENTRY(memcpy)
131         pushl   %esi
132         pushl   %edi
133         movl    4+8(%esp),%edi
134         movl    8+8(%esp),%esi
135         movl    12+8(%esp),%ecx
136         call    *memcpy_vector
137         movl    4+8(%esp),%eax
138         popl    %edi
139         popl    %esi
140         ret
141
142 /*
143  * A stack-based on-fault routine is used for more complex PCB_ONFAULT
144  * situations (such as memcpy/bcopy/bzero).  In this case the on-fault
145  * routine must be pushed on the stack.
146  */
147 stack_onfault:
148         ret
149
150 /*****************************************************************************/
151 /* copyout and fubyte family                                                 */
152 /*****************************************************************************/
153 /*
154  * Access user memory from inside the kernel. These routines and possibly
155  * the math- and DOS emulators should be the only places that do this.
156  *
157  * We have to access the memory with user's permissions, so use a segment
158  * selector with RPL 3. For writes to user space we have to additionally
159  * check the PTE for write permission, because the 386 does not check
160  * write permissions when we are executing with EPL 0. The 486 does check
161  * this if the WP bit is set in CR0, so we can use a simpler version here.
162  *
163  * These routines set curpcb->onfault for the time they execute. When a
164  * protection violation occurs inside the functions, the trap handler
165  * returns to *curpcb->onfault instead of the function.
166  */
167
168 /*
169  * copyout(from_kernel, to_user, len)  - MP SAFE (if not I386_CPU)
170  */
171 ENTRY(copyout)
172         movl    PCPU(curthread),%eax
173         movl    TD_PCB(%eax),%eax
174         pushl   %esi
175         pushl   %edi
176         pushl   %ebx
177         pushl   $copyout_fault2
178         movl    $stack_onfault,PCB_ONFAULT(%eax)
179         movl    4+16(%esp),%esi
180         movl    8+16(%esp),%edi
181         movl    12+16(%esp),%ebx
182         testl   %ebx,%ebx                       /* anything to do? */
183         jz      done_copyout
184
185         /*
186          * Check explicitly for non-user addresses.  If 486 write protection
187          * is being used, this check is essential because we are in kernel
188          * mode so the h/w does not provide any protection against writing
189          * kernel addresses.
190          */
191
192         /*
193          * First, prevent address wrapping.
194          */
195         movl    %edi,%eax
196         addl    %ebx,%eax
197         jc      copyout_fault1
198 /*
199  * XXX STOP USING VM_MAXUSER_ADDRESS.
200  * It is an end address, not a max, so every time it is used correctly it
201  * looks like there is an off by one error, and of course it caused an off
202  * by one error in several places.
203  */
204         cmpl    $VM_MAXUSER_ADDRESS,%eax
205         ja      copyout_fault1
206
207 #if defined(I386_CPU)
208
209 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
210         cmpl    $CPUCLASS_386,cpu_class
211         jne     3f
212 #endif
213 /*
214  * We have to check each PTE for user write permission.
215  * The checking may cause a page fault, so it is important to set
216  * up everything for return via copyout_fault before here.
217  */
218         /* compute number of pages */
219         movl    %edi,%ecx
220         andl    $PAGE_MASK,%ecx
221         addl    %ebx,%ecx
222         decl    %ecx
223         shrl    $IDXSHIFT+2,%ecx
224         incl    %ecx
225
226         /* compute PTE offset for start address */
227         movl    %edi,%edx
228         shrl    $IDXSHIFT,%edx
229         andb    $0xfc,%dl
230
231 1:
232         /* check PTE for each page */
233         leal    PTmap(%edx),%eax
234         shrl    $IDXSHIFT,%eax
235         andb    $0xfc,%al
236         testb   $PG_V,PTmap(%eax)               /* PTE page must be valid */
237         je      4f
238         movb    PTmap(%edx),%al
239         andb    $PG_V|PG_RW|PG_U,%al            /* page must be valid and user writable */
240         cmpb    $PG_V|PG_RW|PG_U,%al
241         je      2f
242
243 4:
244         /* simulate a trap */
245         pushl   %edx
246         pushl   %ecx
247         shll    $IDXSHIFT,%edx
248         pushl   %edx
249         call    trapwrite                       /* trapwrite(addr) */
250         popl    %edx
251         popl    %ecx
252         popl    %edx
253
254         testl   %eax,%eax                       /* if not ok, return EFAULT */
255         jnz     copyout_fault1
256
257 2:
258         addl    $4,%edx
259         decl    %ecx
260         jnz     1b                              /* check next page */
261 #endif /* I386_CPU */
262
263         /*
264          * Convert copyout to memcpy_vector(dest:%edi, src:%esi, conut:%ecx)
265          */
266 3:
267         movl    %ebx,%ecx
268         call    *memcpy_vector
269
270 done_copyout:
271         /*
272          * non-error return
273          */
274         addl    $4,%esp
275         movl    PCPU(curthread),%edx
276         xorl    %eax,%eax
277         movl    TD_PCB(%edx),%edx
278         popl    %ebx
279         popl    %edi
280         popl    %esi
281         movl    %eax,PCB_ONFAULT(%edx)
282         ret
283
284         ALIGN_TEXT
285 copyout_fault1:
286         addl    $4,%esp         /* skip pushed copyout_fault vector */
287 copyout_fault2:
288         popl    %ebx
289         popl    %edi
290         popl    %esi
291         movl    PCPU(curthread),%edx
292         movl    TD_PCB(%edx),%edx
293         movl    $0,PCB_ONFAULT(%edx)
294         movl    $EFAULT,%eax
295         ret
296
297 /*
298  * copyin(from_user, to_kernel, len) - MP SAFE
299  */
300
301 ENTRY(copyin)
302         movl    PCPU(curthread),%eax
303         movl    TD_PCB(%eax),%eax
304         pushl   %esi
305         pushl   %edi
306         pushl   $copyin_fault2
307         movl    $stack_onfault,PCB_ONFAULT(%eax)
308         movl    4+12(%esp),%esi                 /* caddr_t from */
309         movl    8+12(%esp),%edi                 /* caddr_t to */
310         movl    12+12(%esp),%ecx                /* size_t  len */
311
312         /*
313          * make sure address is valid
314          */
315         movl    %esi,%edx
316         addl    %ecx,%edx
317         jc      copyin_fault1
318         cmpl    $VM_MAXUSER_ADDRESS,%edx
319         ja      copyin_fault1
320
321         /*
322          * Call memcpy(destination:%edi, source:%esi, bytes:%ecx)
323          */
324         call    *memcpy_vector
325
326         /*
327          * return 0 (no error)
328          */
329         addl    $4,%esp
330         movl    PCPU(curthread),%edx
331         xorl    %eax,%eax
332         movl    TD_PCB(%edx),%edx
333         popl    %edi
334         popl    %esi
335         movl    %eax,PCB_ONFAULT(%edx)
336         ret
337
338         /*
339          * return EFAULT
340          */
341         ALIGN_TEXT
342 copyin_fault1:
343         addl    $4,%esp         /* skip pushed copyin_fault vector */
344 copyin_fault2:
345         popl    %edi
346         popl    %esi
347         movl    PCPU(curthread),%edx
348         movl    TD_PCB(%edx),%edx
349         movl    $0,PCB_ONFAULT(%edx)
350         movl    $EFAULT,%eax
351         ret
352
353 /*
354  * fu{byte,sword,word} - MP SAFE
355  *
356  *      Fetch a byte (sword, word) from user memory
357  */
358 ENTRY(fuword)
359         movl    PCPU(curthread),%ecx
360         movl    TD_PCB(%ecx),%ecx
361         movl    $fusufault,PCB_ONFAULT(%ecx)
362         movl    4(%esp),%edx                    /* from */
363
364         cmpl    $VM_MAXUSER_ADDRESS-4,%edx      /* verify address is valid */
365         ja      fusufault
366
367         movl    (%edx),%eax
368         movl    $0,PCB_ONFAULT(%ecx)
369         ret
370
371 /*
372  * These two routines are called from the profiling code, potentially
373  * at interrupt time. If they fail, that's okay, good things will
374  * happen later. Fail all the time for now - until the trap code is
375  * able to deal with this.
376  */
377 ALTENTRY(suswintr)
378 ENTRY(fuswintr)
379         movl    $-1,%eax
380         ret
381
382 /*
383  * fusword - MP SAFE
384  */
385 ENTRY(fusword)
386         movl    PCPU(curthread),%ecx
387         movl    TD_PCB(%ecx),%ecx
388         movl    $fusufault,PCB_ONFAULT(%ecx)
389         movl    4(%esp),%edx
390
391         cmpl    $VM_MAXUSER_ADDRESS-2,%edx
392         ja      fusufault
393
394         movzwl  (%edx),%eax
395         movl    $0,PCB_ONFAULT(%ecx)
396         ret
397
398 /*
399  * fubyte - MP SAFE
400  */
401 ENTRY(fubyte)
402         movl    PCPU(curthread),%ecx
403         movl    TD_PCB(%ecx),%ecx
404         movl    $fusufault,PCB_ONFAULT(%ecx)
405         movl    4(%esp),%edx
406
407         cmpl    $VM_MAXUSER_ADDRESS-1,%edx
408         ja      fusufault
409
410         movzbl  (%edx),%eax
411         movl    $0,PCB_ONFAULT(%ecx)
412         ret
413
414         ALIGN_TEXT
415 fusufault:
416         movl    PCPU(curthread),%ecx
417         movl    TD_PCB(%ecx),%ecx
418         xorl    %eax,%eax
419         movl    %eax,PCB_ONFAULT(%ecx)
420         decl    %eax
421         ret
422
423 /*
424  * su{byte,sword,word} - MP SAFE (if not I386_CPU)
425  *
426  *      Write a byte (word, longword) to user memory
427  */
428 ENTRY(suword)
429         movl    PCPU(curthread),%ecx
430         movl    TD_PCB(%ecx),%ecx
431         movl    $fusufault,PCB_ONFAULT(%ecx)
432         movl    4(%esp),%edx
433
434 #if defined(I386_CPU)
435
436 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
437         cmpl    $CPUCLASS_386,cpu_class
438         jne     2f                              /* we only have to set the right segment selector */
439 #endif /* I486_CPU || I586_CPU || I686_CPU */
440
441         /* XXX - page boundary crossing is still not handled */
442         movl    %edx,%eax
443         shrl    $IDXSHIFT,%edx
444         andb    $0xfc,%dl
445
446         leal    PTmap(%edx),%ecx
447         shrl    $IDXSHIFT,%ecx
448         andb    $0xfc,%cl
449         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
450         je      4f
451         movb    PTmap(%edx),%dl
452         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
453         cmpb    $PG_V|PG_RW|PG_U,%dl
454         je      1f
455
456 4:
457         /* simulate a trap */
458         pushl   %eax
459         call    trapwrite
460         popl    %edx                            /* remove junk parameter from stack */
461         testl   %eax,%eax
462         jnz     fusufault
463 1:
464         movl    4(%esp),%edx
465 #endif
466
467 2:
468         cmpl    $VM_MAXUSER_ADDRESS-4,%edx      /* verify address validity */
469         ja      fusufault
470
471         movl    8(%esp),%eax
472         movl    %eax,(%edx)
473         xorl    %eax,%eax
474         movl    PCPU(curthread),%ecx
475         movl    TD_PCB(%ecx),%ecx
476         movl    %eax,PCB_ONFAULT(%ecx)
477         ret
478
479 /*
480  * susword - MP SAFE (if not I386_CPU)
481  */
482 ENTRY(susword)
483         movl    PCPU(curthread),%ecx
484         movl    TD_PCB(%ecx),%ecx
485         movl    $fusufault,PCB_ONFAULT(%ecx)
486         movl    4(%esp),%edx
487
488 #if defined(I386_CPU)
489
490 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
491         cmpl    $CPUCLASS_386,cpu_class
492         jne     2f
493 #endif /* I486_CPU || I586_CPU || I686_CPU */
494
495         /* XXX - page boundary crossing is still not handled */
496         movl    %edx,%eax
497         shrl    $IDXSHIFT,%edx
498         andb    $0xfc,%dl
499
500         leal    PTmap(%edx),%ecx
501         shrl    $IDXSHIFT,%ecx
502         andb    $0xfc,%cl
503         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
504         je      4f
505         movb    PTmap(%edx),%dl
506         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
507         cmpb    $PG_V|PG_RW|PG_U,%dl
508         je      1f
509
510 4:
511         /* simulate a trap */
512         pushl   %eax
513         call    trapwrite
514         popl    %edx                            /* remove junk parameter from stack */
515         testl   %eax,%eax
516         jnz     fusufault
517 1:
518         movl    4(%esp),%edx
519 #endif
520
521 2:
522         cmpl    $VM_MAXUSER_ADDRESS-2,%edx      /* verify address validity */
523         ja      fusufault
524
525         movw    8(%esp),%ax
526         movw    %ax,(%edx)
527         xorl    %eax,%eax
528         movl    PCPU(curthread),%ecx                    /* restore trashed register */
529         movl    TD_PCB(%ecx),%ecx
530         movl    %eax,PCB_ONFAULT(%ecx)
531         ret
532
533 /*
534  * su[i]byte - MP SAFE (if not I386_CPU)
535  */
536 ALTENTRY(suibyte)
537 ENTRY(subyte)
538         movl    PCPU(curthread),%ecx
539         movl    TD_PCB(%ecx),%ecx
540         movl    $fusufault,PCB_ONFAULT(%ecx)
541         movl    4(%esp),%edx
542
543 #if defined(I386_CPU)
544
545 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
546         cmpl    $CPUCLASS_386,cpu_class
547         jne     2f
548 #endif /* I486_CPU || I586_CPU || I686_CPU */
549
550         movl    %edx,%eax
551         shrl    $IDXSHIFT,%edx
552         andb    $0xfc,%dl
553
554         leal    PTmap(%edx),%ecx
555         shrl    $IDXSHIFT,%ecx
556         andb    $0xfc,%cl
557         testb   $PG_V,PTmap(%ecx)               /* PTE page must be valid */
558         je      4f
559         movb    PTmap(%edx),%dl
560         andb    $PG_V|PG_RW|PG_U,%dl            /* page must be valid and user writable */
561         cmpb    $PG_V|PG_RW|PG_U,%dl
562         je      1f
563
564 4:
565         /* simulate a trap */
566         pushl   %eax
567         call    trapwrite
568         popl    %edx                            /* remove junk parameter from stack */
569         testl   %eax,%eax
570         jnz     fusufault
571 1:
572         movl    4(%esp),%edx
573 #endif
574
575 2:
576         cmpl    $VM_MAXUSER_ADDRESS-1,%edx      /* verify address validity */
577         ja      fusufault
578
579         movb    8(%esp),%al
580         movb    %al,(%edx)
581         xorl    %eax,%eax
582         movl    PCPU(curthread),%ecx            /* restore trashed register */
583         movl    TD_PCB(%ecx),%ecx
584         movl    %eax,PCB_ONFAULT(%ecx)
585         ret
586
587 /*
588  * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
589  *
590  *      copy a string from from to to, stop when a 0 character is reached.
591  *      return ENAMETOOLONG if string is longer than maxlen, and
592  *      EFAULT on protection violations. If lencopied is non-zero,
593  *      return the actual length in *lencopied.
594  */
595 ENTRY(copyinstr)
596         pushl   %esi
597         pushl   %edi
598         movl    PCPU(curthread),%ecx
599         movl    TD_PCB(%ecx),%ecx
600         movl    $cpystrflt,PCB_ONFAULT(%ecx)
601
602         movl    12(%esp),%esi                   /* %esi = from */
603         movl    16(%esp),%edi                   /* %edi = to */
604         movl    20(%esp),%edx                   /* %edx = maxlen */
605
606         movl    $VM_MAXUSER_ADDRESS,%eax
607
608         /* make sure 'from' is within bounds */
609         subl    %esi,%eax
610         jbe     cpystrflt
611
612         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
613         cmpl    %edx,%eax
614         jae     1f
615         movl    %eax,%edx
616         movl    %eax,20(%esp)
617 1:
618         incl    %edx
619         cld
620
621 2:
622         decl    %edx
623         jz      3f
624
625         lodsb
626         stosb
627         orb     %al,%al
628         jnz     2b
629
630         /* Success -- 0 byte reached */
631         decl    %edx
632         xorl    %eax,%eax
633         jmp     cpystrflt_x
634 3:
635         /* edx is zero - return ENAMETOOLONG or EFAULT */
636         cmpl    $VM_MAXUSER_ADDRESS,%esi
637         jae     cpystrflt
638 4:
639         movl    $ENAMETOOLONG,%eax
640         jmp     cpystrflt_x
641
642 cpystrflt:
643         movl    $EFAULT,%eax
644
645 cpystrflt_x:
646         /* set *lencopied and return %eax */
647         movl    PCPU(curthread),%ecx
648         movl    TD_PCB(%ecx),%ecx
649         movl    $0,PCB_ONFAULT(%ecx)
650         movl    20(%esp),%ecx
651         subl    %edx,%ecx
652         movl    24(%esp),%edx
653         testl   %edx,%edx
654         jz      1f
655         movl    %ecx,(%edx)
656 1:
657         popl    %edi
658         popl    %esi
659         ret
660
661
662 /*
663  * copystr(from, to, maxlen, int *lencopied) - MP SAFE
664  */
665 ENTRY(copystr)
666         pushl   %esi
667         pushl   %edi
668
669         movl    12(%esp),%esi                   /* %esi = from */
670         movl    16(%esp),%edi                   /* %edi = to */
671         movl    20(%esp),%edx                   /* %edx = maxlen */
672         incl    %edx
673         cld
674 1:
675         decl    %edx
676         jz      4f
677         lodsb
678         stosb
679         orb     %al,%al
680         jnz     1b
681
682         /* Success -- 0 byte reached */
683         decl    %edx
684         xorl    %eax,%eax
685         jmp     6f
686 4:
687         /* edx is zero -- return ENAMETOOLONG */
688         movl    $ENAMETOOLONG,%eax
689
690 6:
691         /* set *lencopied and return %eax */
692         movl    20(%esp),%ecx
693         subl    %edx,%ecx
694         movl    24(%esp),%edx
695         testl   %edx,%edx
696         jz      7f
697         movl    %ecx,(%edx)
698 7:
699         popl    %edi
700         popl    %esi
701         ret
702
703 ENTRY(bcmp)
704         pushl   %edi
705         pushl   %esi
706         movl    12(%esp),%edi
707         movl    16(%esp),%esi
708         movl    20(%esp),%edx
709         xorl    %eax,%eax
710
711         movl    %edx,%ecx
712         shrl    $2,%ecx
713         cld                                     /* compare forwards */
714         repe
715         cmpsl
716         jne     1f
717
718         movl    %edx,%ecx
719         andl    $3,%ecx
720         repe
721         cmpsb
722         je      2f
723 1:
724         incl    %eax
725 2:
726         popl    %esi
727         popl    %edi
728         ret
729
730
731 /*
732  * Handling of special 386 registers and descriptor tables etc
733  */
734 /* void lgdt(struct region_descriptor *rdp); */
735 ENTRY(lgdt)
736         /* reload the descriptor table */
737         movl    4(%esp),%eax
738         lgdt    (%eax)
739
740         /* flush the prefetch q */
741         jmp     1f
742         nop
743 1:
744         /* reload "stale" selectors */
745         movl    $KDSEL,%eax
746         mov     %ax,%ds
747         mov     %ax,%es
748         mov     %ax,%gs
749         mov     %ax,%ss
750         movl    $KPSEL,%eax
751         mov     %ax,%fs
752
753         /* reload code selector by turning return into intersegmental return */
754         movl    (%esp),%eax
755         pushl   %eax
756         movl    $KCSEL,4(%esp)
757         lret
758
759 /*
760  * void lidt(struct region_descriptor *rdp);
761  */
762 ENTRY(lidt)
763         movl    4(%esp),%eax
764         lidt    (%eax)
765         ret
766
767 /*
768  * void lldt(u_short sel)
769  */
770 ENTRY(lldt)
771         lldt    4(%esp)
772         ret
773
774 /*
775  * void ltr(u_short sel)
776  */
777 ENTRY(ltr)
778         ltr     4(%esp)
779         ret
780
781 /* ssdtosd(*ssdp,*sdp) */
782 ENTRY(ssdtosd)
783         pushl   %ebx
784         movl    8(%esp),%ecx
785         movl    8(%ecx),%ebx
786         shll    $16,%ebx
787         movl    (%ecx),%edx
788         roll    $16,%edx
789         movb    %dh,%bl
790         movb    %dl,%bh
791         rorl    $8,%ebx
792         movl    4(%ecx),%eax
793         movw    %ax,%dx
794         andl    $0xf0000,%eax
795         orl     %eax,%ebx
796         movl    12(%esp),%ecx
797         movl    %edx,(%ecx)
798         movl    %ebx,4(%ecx)
799         popl    %ebx
800         ret
801
802 /* load_cr0(cr0) */
803 ENTRY(load_cr0)
804         movl    4(%esp),%eax
805         movl    %eax,%cr0
806         ret
807
808 /* rcr0() */
809 ENTRY(rcr0)
810         movl    %cr0,%eax
811         ret
812
813 /* rcr3() */
814 ENTRY(rcr3)
815         movl    %cr3,%eax
816         ret
817
818 /* void load_cr3(caddr_t cr3) */
819 ENTRY(load_cr3)
820 #if defined(SWTCH_OPTIM_STATS)
821         incl    _tlb_flush_count
822 #endif
823         movl    4(%esp),%eax
824         movl    %eax,%cr3
825         ret
826
827 /* rcr4() */
828 ENTRY(rcr4)
829         movl    %cr4,%eax
830         ret
831
832 /* void load_cr4(caddr_t cr4) */
833 ENTRY(load_cr4)
834         movl    4(%esp),%eax
835         movl    %eax,%cr4
836         ret
837
838 /* void reset_dbregs() */
839 ENTRY(reset_dbregs)
840         movl    $0,%eax
841         movl    %eax,%dr7     /* disable all breapoints first */
842         movl    %eax,%dr0
843         movl    %eax,%dr1
844         movl    %eax,%dr2
845         movl    %eax,%dr3
846         movl    %eax,%dr6
847         ret
848
849 /*****************************************************************************/
850 /* setjump, longjump                                                         */
851 /*****************************************************************************/
852
853 ENTRY(setjmp)
854         movl    4(%esp),%eax
855         movl    %ebx,(%eax)                     /* save ebx */
856         movl    %esp,4(%eax)                    /* save esp */
857         movl    %ebp,8(%eax)                    /* save ebp */
858         movl    %esi,12(%eax)                   /* save esi */
859         movl    %edi,16(%eax)                   /* save edi */
860         movl    (%esp),%edx                     /* get rta */
861         movl    %edx,20(%eax)                   /* save eip */
862         xorl    %eax,%eax                       /* return(0); */
863         ret
864
865 ENTRY(longjmp)
866         movl    4(%esp),%eax
867         movl    (%eax),%ebx                     /* restore ebx */
868         movl    4(%eax),%esp                    /* restore esp */
869         movl    8(%eax),%ebp                    /* restore ebp */
870         movl    12(%eax),%esi                   /* restore esi */
871         movl    16(%eax),%edi                   /* restore edi */
872         movl    20(%eax),%edx                   /* get rta */
873         movl    %edx,(%esp)                     /* put in return frame */
874         xorl    %eax,%eax                       /* return(1); */
875         incl    %eax
876         ret
877
878 /*
879  * Support for BB-profiling (gcc -a).  The kernbb program will extract
880  * the data from the kernel.
881  */
882
883         .data
884         ALIGN_DATA
885         .globl bbhead
886 bbhead:
887         .long 0
888
889         .text
890 NON_GPROF_ENTRY(__bb_init_func)
891         movl    4(%esp),%eax
892         movl    $1,(%eax)
893         movl    bbhead,%edx
894         movl    %edx,16(%eax)
895         movl    %eax,bbhead
896         .byte   0xc3                            /* avoid macro for `ret' */