Enhance debugging (sync before MP work).
[dragonfly.git] / sys / platform / pc32 / i386 / support.s
CommitLineData
984263bc
MD
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 $
17a9f566 34 * $DragonFly: src/sys/platform/pc32/i386/support.s,v 1.6 2003/06/28 02:09:47 dillon Exp $
984263bc
MD
35 */
36
37#include "npx.h"
38
39#include <machine/asmacros.h>
40#include <machine/cputypes.h>
41#include <machine/pmap.h>
42#include <machine/specialreg.h>
43
44#include "assym.s"
45
46#define IDXSHIFT 10
47
48 .data
49 .globl _bcopy_vector
50_bcopy_vector:
51 .long _generic_bcopy
52 .globl _bzero
53_bzero:
54 .long _generic_bzero
55 .globl _copyin_vector
56_copyin_vector:
57 .long _generic_copyin
58 .globl _copyout_vector
59_copyout_vector:
60 .long _generic_copyout
61 .globl _ovbcopy_vector
62_ovbcopy_vector:
63 .long _generic_bcopy
64#if defined(I586_CPU) && NNPX > 0
65kernel_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
77ENTRY(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)
94ENTRY(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 */
1032:
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
1313:
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
1474:
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
163jtab:
164 .long do0
165 .long do1
166 .long do2
167 .long do3
168
169 .text
170 SUPERALIGN_TEXT
1715:
172 jmp *jtab(,%ecx,4)
173
174 SUPERALIGN_TEXT
175do3:
176 movw %ax,(%edx)
177 movb %al,2(%edx)
178 ret
179
180 SUPERALIGN_TEXT
181do2:
182 movw %ax,(%edx)
183 ret
184
185 SUPERALIGN_TEXT
186do1:
187 movb %al,(%edx)
188 ret
189
190 SUPERALIGN_TEXT
191do0:
192 ret
193#endif
194
195#if defined(I586_CPU) && NNPX > 0
196ENTRY(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.
af0bff84
MD
220 * `npxthread != NULL' is supposed to be the condition that all the
221 * FPU resources belong to an application, but npxthread and CR0_TS
984263bc
MD
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 */
af0bff84 245 cmpl $0,_npxthread
984263bc
MD
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
257i586_bz1:
258 sarb $1,kernel_fpu_lock
259 jc intreg_i586_bzero
260 smsw %ax
261 clts
262 fninit /* XXX should avoid needing this */
263i586_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 */
290fpureg_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
af0bff84 297 cmpl $0,_npxthread
984263bc
MD
298 je i586_bz3
299 frstor 0(%esp)
300 addl $108,%esp
301 lmsw %ax
302 movb $0xfe,kernel_fpu_lock
303 ret
304
305i586_bz3:
306 fstp %st(0)
307 lmsw %ax
308 movb $0xfe,kernel_fpu_lock
309 ret
310
311intreg_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
3301:
331 rep
332 stosb
333 popl %edi
334 ret
335#endif /* I586_CPU && NNPX > 0 */
336
337ENTRY(i686_pagezero)
338 pushl %edi
339 pushl %ebx
340
341 movl 12(%esp), %edi
342 movl $1024, %ecx
343 cld
344
345 ALIGN_TEXT
3461:
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
3582:
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
3743:
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) */
388ENTRY(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
399ENTRY(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
4171:
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
430ENTRY(bcopy)
431 MEXITCOUNT
432 jmp *_bcopy_vector
433
434ENTRY(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 */
442ENTRY(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
4671:
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
488ENTRY(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
af0bff84 505 cmpl $0,_npxthread
984263bc
MD
506 je i586_bc1
507 smsw %dx
508 clts
509 subl $108,%esp
510 fnsave 0(%esp)
511 jmp 4f
512
513i586_bc1:
514 smsw %dx
515 clts
516 fninit /* XXX should avoid needing this */
517
518 ALIGN_TEXT
5194:
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
5252:
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
5323:
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
5475:
548 ALIGN_TEXT
549large_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
af0bff84 576 cmpl $0,_npxthread
984263bc
MD
577 je i586_bc2
578 frstor 0(%esp)
579 addl $108,%esp
580i586_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
590small_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
6041:
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 */
628ENTRY(memcpy)
629 pushl %edi
630 pushl %esi
631 movl 12(%esp),%edi
632 movl 16(%esp),%esi
633 movl 20(%esp),%ecx
634 movl %edi,%eax
635 shrl $2,%ecx /* copy by 32-bit words */
636 cld /* nope, copy forwards */
637 rep
638 movsl
639 movl 20(%esp),%ecx
640 andl $3,%ecx /* any bytes left? */
641 rep
642 movsb
643 popl %esi
644 popl %edi
645 ret
646
647
648/*****************************************************************************/
649/* copyout and fubyte family */
650/*****************************************************************************/
651/*
652 * Access user memory from inside the kernel. These routines and possibly
653 * the math- and DOS emulators should be the only places that do this.
654 *
655 * We have to access the memory with user's permissions, so use a segment
656 * selector with RPL 3. For writes to user space we have to additionally
657 * check the PTE for write permission, because the 386 does not check
658 * write permissions when we are executing with EPL 0. The 486 does check
659 * this if the WP bit is set in CR0, so we can use a simpler version here.
660 *
661 * These routines set curpcb->onfault for the time they execute. When a
662 * protection violation occurs inside the functions, the trap handler
663 * returns to *curpcb->onfault instead of the function.
664 */
665
666/*
667 * copyout(from_kernel, to_user, len) - MP SAFE (if not I386_CPU)
668 */
669ENTRY(copyout)
670 MEXITCOUNT
671 jmp *_copyout_vector
672
673ENTRY(generic_copyout)
b7c628e4
MD
674 movl _curthread,%eax
675 movl TD_PCB(%eax),%eax
984263bc
MD
676 movl $copyout_fault,PCB_ONFAULT(%eax)
677 pushl %esi
678 pushl %edi
679 pushl %ebx
680 movl 16(%esp),%esi
681 movl 20(%esp),%edi
682 movl 24(%esp),%ebx
683 testl %ebx,%ebx /* anything to do? */
684 jz done_copyout
685
686 /*
687 * Check explicitly for non-user addresses. If 486 write protection
688 * is being used, this check is essential because we are in kernel
689 * mode so the h/w does not provide any protection against writing
690 * kernel addresses.
691 */
692
693 /*
694 * First, prevent address wrapping.
695 */
696 movl %edi,%eax
697 addl %ebx,%eax
698 jc copyout_fault
699/*
700 * XXX STOP USING VM_MAXUSER_ADDRESS.
701 * It is an end address, not a max, so every time it is used correctly it
702 * looks like there is an off by one error, and of course it caused an off
703 * by one error in several places.
704 */
705 cmpl $VM_MAXUSER_ADDRESS,%eax
706 ja copyout_fault
707
708#if defined(I386_CPU)
709
710#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
711 cmpl $CPUCLASS_386,_cpu_class
712 jne 3f
713#endif
714/*
715 * We have to check each PTE for user write permission.
716 * The checking may cause a page fault, so it is important to set
717 * up everything for return via copyout_fault before here.
718 */
719 /* compute number of pages */
720 movl %edi,%ecx
721 andl $PAGE_MASK,%ecx
722 addl %ebx,%ecx
723 decl %ecx
724 shrl $IDXSHIFT+2,%ecx
725 incl %ecx
726
727 /* compute PTE offset for start address */
728 movl %edi,%edx
729 shrl $IDXSHIFT,%edx
730 andb $0xfc,%dl
731
7321:
733 /* check PTE for each page */
734 leal _PTmap(%edx),%eax
735 shrl $IDXSHIFT,%eax
736 andb $0xfc,%al
737 testb $PG_V,_PTmap(%eax) /* PTE page must be valid */
738 je 4f
739 movb _PTmap(%edx),%al
740 andb $PG_V|PG_RW|PG_U,%al /* page must be valid and user writable */
741 cmpb $PG_V|PG_RW|PG_U,%al
742 je 2f
743
7444:
745 /* simulate a trap */
746 pushl %edx
747 pushl %ecx
748 shll $IDXSHIFT,%edx
749 pushl %edx
750 call _trapwrite /* trapwrite(addr) */
751 popl %edx
752 popl %ecx
753 popl %edx
754
755 testl %eax,%eax /* if not ok, return EFAULT */
756 jnz copyout_fault
757
7582:
759 addl $4,%edx
760 decl %ecx
761 jnz 1b /* check next page */
762#endif /* I386_CPU */
763
764 /* bcopy(%esi, %edi, %ebx) */
7653:
766 movl %ebx,%ecx
767
768#if defined(I586_CPU) && NNPX > 0
769 ALIGN_TEXT
770slow_copyout:
771#endif
772 shrl $2,%ecx
773 cld
774 rep
775 movsl
776 movb %bl,%cl
777 andb $3,%cl
778 rep
779 movsb
780
781done_copyout:
782 popl %ebx
783 popl %edi
784 popl %esi
785 xorl %eax,%eax
b7c628e4
MD
786 movl _curthread,%edx
787 movl TD_PCB(%edx),%edx
984263bc
MD
788 movl %eax,PCB_ONFAULT(%edx)
789 ret
790
791 ALIGN_TEXT
792copyout_fault:
793 popl %ebx
794 popl %edi
795 popl %esi
b7c628e4
MD
796 movl _curthread,%edx
797 movl TD_PCB(%edx),%edx
984263bc
MD
798 movl $0,PCB_ONFAULT(%edx)
799 movl $EFAULT,%eax
800 ret
801
802#if defined(I586_CPU) && NNPX > 0
803ENTRY(i586_copyout)
804 /*
805 * Duplicated from generic_copyout. Could be done a bit better.
806 */
b7c628e4
MD
807 movl _curthread,%eax
808 movl TD_PCB(%eax),%eax
984263bc
MD
809 movl $copyout_fault,PCB_ONFAULT(%eax)
810 pushl %esi
811 pushl %edi
812 pushl %ebx
813 movl 16(%esp),%esi
814 movl 20(%esp),%edi
815 movl 24(%esp),%ebx
816 testl %ebx,%ebx /* anything to do? */
817 jz done_copyout
818
819 /*
820 * Check explicitly for non-user addresses. If 486 write protection
821 * is being used, this check is essential because we are in kernel
822 * mode so the h/w does not provide any protection against writing
823 * kernel addresses.
824 */
825
826 /*
827 * First, prevent address wrapping.
828 */
829 movl %edi,%eax
830 addl %ebx,%eax
831 jc copyout_fault
832/*
833 * XXX STOP USING VM_MAXUSER_ADDRESS.
834 * It is an end address, not a max, so every time it is used correctly it
835 * looks like there is an off by one error, and of course it caused an off
836 * by one error in several places.
837 */
838 cmpl $VM_MAXUSER_ADDRESS,%eax
839 ja copyout_fault
840
841 /* bcopy(%esi, %edi, %ebx) */
8423:
843 movl %ebx,%ecx
844 /*
845 * End of duplicated code.
846 */
847
848 cmpl $1024,%ecx
849 jb slow_copyout
850
851 pushl %ecx
852 call _fastmove
853 addl $4,%esp
854 jmp done_copyout
855#endif /* I586_CPU && NNPX > 0 */
856
857/*
858 * copyin(from_user, to_kernel, len) - MP SAFE
859 */
860ENTRY(copyin)
861 MEXITCOUNT
862 jmp *_copyin_vector
863
864ENTRY(generic_copyin)
b7c628e4
MD
865 movl _curthread,%eax
866 movl TD_PCB(%eax),%eax
984263bc
MD
867 movl $copyin_fault,PCB_ONFAULT(%eax)
868 pushl %esi
869 pushl %edi
870 movl 12(%esp),%esi /* caddr_t from */
871 movl 16(%esp),%edi /* caddr_t to */
872 movl 20(%esp),%ecx /* size_t len */
873
874 /*
875 * make sure address is valid
876 */
877 movl %esi,%edx
878 addl %ecx,%edx
879 jc copyin_fault
880 cmpl $VM_MAXUSER_ADDRESS,%edx
881 ja copyin_fault
882
883#if defined(I586_CPU) && NNPX > 0
884 ALIGN_TEXT
885slow_copyin:
886#endif
887 movb %cl,%al
888 shrl $2,%ecx /* copy longword-wise */
889 cld
890 rep
891 movsl
892 movb %al,%cl
893 andb $3,%cl /* copy remaining bytes */
894 rep
895 movsb
896
897#if defined(I586_CPU) && NNPX > 0
898 ALIGN_TEXT
899done_copyin:
900#endif
901 popl %edi
902 popl %esi
903 xorl %eax,%eax
b7c628e4
MD
904 movl _curthread,%edx
905 movl TD_PCB(%edx),%edx
984263bc
MD
906 movl %eax,PCB_ONFAULT(%edx)
907 ret
908
909 ALIGN_TEXT
910copyin_fault:
911 popl %edi
912 popl %esi
b7c628e4
MD
913 movl _curthread,%edx
914 movl TD_PCB(%edx),%edx
984263bc
MD
915 movl $0,PCB_ONFAULT(%edx)
916 movl $EFAULT,%eax
917 ret
918
919#if defined(I586_CPU) && NNPX > 0
920ENTRY(i586_copyin)
921 /*
922 * Duplicated from generic_copyin. Could be done a bit better.
923 */
b7c628e4
MD
924 movl _curthread,%eax
925 movl TD_PCB(%eax),%eax
984263bc
MD
926 movl $copyin_fault,PCB_ONFAULT(%eax)
927 pushl %esi
928 pushl %edi
929 movl 12(%esp),%esi /* caddr_t from */
930 movl 16(%esp),%edi /* caddr_t to */
931 movl 20(%esp),%ecx /* size_t len */
932
933 /*
934 * make sure address is valid
935 */
936 movl %esi,%edx
937 addl %ecx,%edx
938 jc copyin_fault
939 cmpl $VM_MAXUSER_ADDRESS,%edx
940 ja copyin_fault
941 /*
942 * End of duplicated code.
943 */
944
945 cmpl $1024,%ecx
946 jb slow_copyin
947
948 pushl %ebx /* XXX prepare for fastmove_fault */
949 pushl %ecx
950 call _fastmove
951 addl $8,%esp
952 jmp done_copyin
953#endif /* I586_CPU && NNPX > 0 */
954
955#if defined(I586_CPU) && NNPX > 0
956/* fastmove(src, dst, len)
957 src in %esi
958 dst in %edi
959 len in %ecx XXX changed to on stack for profiling
960 uses %eax and %edx for tmp. storage
961 */
962/* XXX use ENTRY() to get profiling. fastmove() is actually a non-entry. */
963ENTRY(fastmove)
964 pushl %ebp
965 movl %esp,%ebp
966 subl $PCB_SAVE87_SIZE+3*4,%esp
967
968 movl 8(%ebp),%ecx
969 cmpl $63,%ecx
970 jbe fastmove_tail
971
972 testl $7,%esi /* check if src addr is multiple of 8 */
973 jnz fastmove_tail
974
975 testl $7,%edi /* check if dst addr is multiple of 8 */
976 jnz fastmove_tail
977
af0bff84
MD
978/* if (npxthread != NULL) { */
979 cmpl $0,_npxthread
984263bc
MD
980 je 6f
981/* fnsave(&curpcb->pcb_savefpu); */
b7c628e4
MD
982 movl _curthread,%eax
983 movl TD_PCB(%eax),%eax
984263bc 984 fnsave PCB_SAVEFPU(%eax)
af0bff84
MD
985/* npxthread = NULL; */
986 movl $0,_npxthread
984263bc
MD
987/* } */
9886:
989/* now we own the FPU. */
990
991/*
992 * The process' FP state is saved in the pcb, but if we get
993 * switched, the cpu_switch() will store our FP state in the
994 * pcb. It should be possible to avoid all the copying for
995 * this, e.g., by setting a flag to tell cpu_switch() to
996 * save the state somewhere else.
997 */
998/* tmp = curpcb->pcb_savefpu; */
999 movl %ecx,-12(%ebp)
1000 movl %esi,-8(%ebp)
1001 movl %edi,-4(%ebp)
1002 movl %esp,%edi
b7c628e4
MD
1003 movl _curthread,%esi
1004 movl TD_PCB(%esi),%esi
984263bc
MD
1005 addl $PCB_SAVEFPU,%esi
1006 cld
1007 movl $PCB_SAVE87_SIZE>>2,%ecx
1008 rep
1009 movsl
1010 movl -12(%ebp),%ecx
1011 movl -8(%ebp),%esi
1012 movl -4(%ebp),%edi
1013/* stop_emulating(); */
1014 clts
af0bff84 1015/* npxthread = curthread; */
84b592ba 1016 movl _curthread,%eax
af0bff84 1017 movl %eax,_npxthread
b7c628e4
MD
1018 movl _curthread,%eax
1019 movl TD_PCB(%eax),%eax
984263bc
MD
1020 movl $fastmove_fault,PCB_ONFAULT(%eax)
10214:
1022 movl %ecx,-12(%ebp)
1023 cmpl $1792,%ecx
1024 jbe 2f
1025 movl $1792,%ecx
10262:
1027 subl %ecx,-12(%ebp)
1028 cmpl $256,%ecx
1029 jb 5f
1030 movl %ecx,-8(%ebp)
1031 movl %esi,-4(%ebp)
1032 ALIGN_TEXT
10333:
1034 movl 0(%esi),%eax
1035 movl 32(%esi),%eax
1036 movl 64(%esi),%eax
1037 movl 96(%esi),%eax
1038 movl 128(%esi),%eax
1039 movl 160(%esi),%eax
1040 movl 192(%esi),%eax
1041 movl 224(%esi),%eax
1042 addl $256,%esi
1043 subl $256,%ecx
1044 cmpl $256,%ecx
1045 jae 3b
1046 movl -8(%ebp),%ecx
1047 movl -4(%ebp),%esi
10485:
1049 ALIGN_TEXT
1050fastmove_loop:
1051 fildq 0(%esi)
1052 fildq 8(%esi)
1053 fildq 16(%esi)
1054 fildq 24(%esi)
1055 fildq 32(%esi)
1056 fildq 40(%esi)
1057 fildq 48(%esi)
1058 fildq 56(%esi)
1059 fistpq 56(%edi)
1060 fistpq 48(%edi)
1061 fistpq 40(%edi)
1062 fistpq 32(%edi)
1063 fistpq 24(%edi)
1064 fistpq 16(%edi)
1065 fistpq 8(%edi)
1066 fistpq 0(%edi)
1067 addl $-64,%ecx
1068 addl $64,%esi
1069 addl $64,%edi
1070 cmpl $63,%ecx
1071 ja fastmove_loop
1072 movl -12(%ebp),%eax
1073 addl %eax,%ecx
1074 cmpl $64,%ecx
1075 jae 4b
1076
1077/* curpcb->pcb_savefpu = tmp; */
1078 movl %ecx,-12(%ebp)
1079 movl %esi,-8(%ebp)
1080 movl %edi,-4(%ebp)
b7c628e4
MD
1081 movl _curthread,%edi
1082 movl TD_PCB(%edi),%edi
984263bc
MD
1083 addl $PCB_SAVEFPU,%edi
1084 movl %esp,%esi
1085 cld
1086 movl $PCB_SAVE87_SIZE>>2,%ecx
1087 rep
1088 movsl
1089 movl -12(%ebp),%ecx
1090 movl -8(%ebp),%esi
1091 movl -4(%ebp),%edi
1092
1093/* start_emulating(); */
1094 smsw %ax
1095 orb $CR0_TS,%al
1096 lmsw %ax
af0bff84
MD
1097/* npxthread = NULL; */
1098 movl $0,_npxthread
984263bc
MD
1099
1100 ALIGN_TEXT
1101fastmove_tail:
b7c628e4
MD
1102 movl _curthread,%eax
1103 movl TD_PCB(%eax),%eax
984263bc
MD
1104 movl $fastmove_tail_fault,PCB_ONFAULT(%eax)
1105
1106 movb %cl,%al
1107 shrl $2,%ecx /* copy longword-wise */
1108 cld
1109 rep
1110 movsl
1111 movb %al,%cl
1112 andb $3,%cl /* copy remaining bytes */
1113 rep
1114 movsb
1115
1116 movl %ebp,%esp
1117 popl %ebp
1118 ret
1119
1120 ALIGN_TEXT
1121fastmove_fault:
b7c628e4
MD
1122 movl _curthread,%edi
1123 movl TD_PCB(%edi),%edi
984263bc
MD
1124 addl $PCB_SAVEFPU,%edi
1125 movl %esp,%esi
1126 cld
1127 movl $PCB_SAVE87_SIZE>>2,%ecx
1128 rep
1129 movsl
1130
1131 smsw %ax
1132 orb $CR0_TS,%al
1133 lmsw %ax
af0bff84 1134 movl $0,_npxthread
984263bc
MD
1135
1136fastmove_tail_fault:
1137 movl %ebp,%esp
1138 popl %ebp
1139 addl $8,%esp
1140 popl %ebx
1141 popl %edi
1142 popl %esi
b7c628e4
MD
1143 movl _curthread,%edx
1144 movl TD_PCB(%edx),%edx
984263bc
MD
1145 movl $0,PCB_ONFAULT(%edx)
1146 movl $EFAULT,%eax
1147 ret
1148#endif /* I586_CPU && NNPX > 0 */
1149
1150/*
1151 * fu{byte,sword,word} - MP SAFE
1152 *
1153 * Fetch a byte (sword, word) from user memory
1154 */
1155ENTRY(fuword)
b7c628e4
MD
1156 movl _curthread,%ecx
1157 movl TD_PCB(%ecx),%ecx
984263bc
MD
1158 movl $fusufault,PCB_ONFAULT(%ecx)
1159 movl 4(%esp),%edx /* from */
1160
1161 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */
1162 ja fusufault
1163
1164 movl (%edx),%eax
1165 movl $0,PCB_ONFAULT(%ecx)
1166 ret
1167
1168/*
1169 * These two routines are called from the profiling code, potentially
1170 * at interrupt time. If they fail, that's okay, good things will
1171 * happen later. Fail all the time for now - until the trap code is
1172 * able to deal with this.
1173 */
1174ALTENTRY(suswintr)
1175ENTRY(fuswintr)
1176 movl $-1,%eax
1177 ret
1178
1179/*
1180 * fusword - MP SAFE
1181 */
1182ENTRY(fusword)
b7c628e4
MD
1183 movl _curthread,%ecx
1184 movl TD_PCB(%ecx),%ecx
984263bc
MD
1185 movl $fusufault,PCB_ONFAULT(%ecx)
1186 movl 4(%esp),%edx
1187
1188 cmpl $VM_MAXUSER_ADDRESS-2,%edx
1189 ja fusufault
1190
1191 movzwl (%edx),%eax
1192 movl $0,PCB_ONFAULT(%ecx)
1193 ret
1194
1195/*
1196 * fubyte - MP SAFE
1197 */
1198ENTRY(fubyte)
b7c628e4
MD
1199 movl _curthread,%ecx
1200 movl TD_PCB(%ecx),%ecx
984263bc
MD
1201 movl $fusufault,PCB_ONFAULT(%ecx)
1202 movl 4(%esp),%edx
1203
1204 cmpl $VM_MAXUSER_ADDRESS-1,%edx
1205 ja fusufault
1206
1207 movzbl (%edx),%eax
1208 movl $0,PCB_ONFAULT(%ecx)
1209 ret
1210
1211 ALIGN_TEXT
1212fusufault:
b7c628e4
MD
1213 movl _curthread,%ecx
1214 movl TD_PCB(%ecx),%ecx
984263bc
MD
1215 xorl %eax,%eax
1216 movl %eax,PCB_ONFAULT(%ecx)
1217 decl %eax
1218 ret
1219
1220/*
1221 * su{byte,sword,word} - MP SAFE (if not I386_CPU)
1222 *
1223 * Write a byte (word, longword) to user memory
1224 */
1225ENTRY(suword)
b7c628e4
MD
1226 movl _curthread,%ecx
1227 movl TD_PCB(%ecx),%ecx
984263bc
MD
1228 movl $fusufault,PCB_ONFAULT(%ecx)
1229 movl 4(%esp),%edx
1230
1231#if defined(I386_CPU)
1232
1233#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1234 cmpl $CPUCLASS_386,_cpu_class
1235 jne 2f /* we only have to set the right segment selector */
1236#endif /* I486_CPU || I586_CPU || I686_CPU */
1237
1238 /* XXX - page boundary crossing is still not handled */
1239 movl %edx,%eax
1240 shrl $IDXSHIFT,%edx
1241 andb $0xfc,%dl
1242
1243 leal _PTmap(%edx),%ecx
1244 shrl $IDXSHIFT,%ecx
1245 andb $0xfc,%cl
1246 testb $PG_V,_PTmap(%ecx) /* PTE page must be valid */
1247 je 4f
1248 movb _PTmap(%edx),%dl
1249 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1250 cmpb $PG_V|PG_RW|PG_U,%dl
1251 je 1f
1252
12534:
1254 /* simulate a trap */
1255 pushl %eax
1256 call _trapwrite
1257 popl %edx /* remove junk parameter from stack */
1258 testl %eax,%eax
1259 jnz fusufault
12601:
1261 movl 4(%esp),%edx
1262#endif
1263
12642:
1265 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address validity */
1266 ja fusufault
1267
1268 movl 8(%esp),%eax
1269 movl %eax,(%edx)
1270 xorl %eax,%eax
b7c628e4
MD
1271 movl _curthread,%ecx
1272 movl TD_PCB(%ecx),%ecx
984263bc
MD
1273 movl %eax,PCB_ONFAULT(%ecx)
1274 ret
1275
1276/*
1277 * susword - MP SAFE (if not I386_CPU)
1278 */
1279ENTRY(susword)
b7c628e4
MD
1280 movl _curthread,%ecx
1281 movl TD_PCB(%ecx),%ecx
984263bc
MD
1282 movl $fusufault,PCB_ONFAULT(%ecx)
1283 movl 4(%esp),%edx
1284
1285#if defined(I386_CPU)
1286
1287#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1288 cmpl $CPUCLASS_386,_cpu_class
1289 jne 2f
1290#endif /* I486_CPU || I586_CPU || I686_CPU */
1291
1292 /* XXX - page boundary crossing is still not handled */
1293 movl %edx,%eax
1294 shrl $IDXSHIFT,%edx
1295 andb $0xfc,%dl
1296
1297 leal _PTmap(%edx),%ecx
1298 shrl $IDXSHIFT,%ecx
1299 andb $0xfc,%cl
1300 testb $PG_V,_PTmap(%ecx) /* PTE page must be valid */
1301 je 4f
1302 movb _PTmap(%edx),%dl
1303 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1304 cmpb $PG_V|PG_RW|PG_U,%dl
1305 je 1f
1306
13074:
1308 /* simulate a trap */
1309 pushl %eax
1310 call _trapwrite
1311 popl %edx /* remove junk parameter from stack */
1312 testl %eax,%eax
1313 jnz fusufault
13141:
1315 movl 4(%esp),%edx
1316#endif
1317
13182:
1319 cmpl $VM_MAXUSER_ADDRESS-2,%edx /* verify address validity */
1320 ja fusufault
1321
1322 movw 8(%esp),%ax
1323 movw %ax,(%edx)
1324 xorl %eax,%eax
b7c628e4
MD
1325 movl _curthread,%ecx /* restore trashed register */
1326 movl TD_PCB(%ecx),%ecx
984263bc
MD
1327 movl %eax,PCB_ONFAULT(%ecx)
1328 ret
1329
1330/*
1331 * su[i]byte - MP SAFE (if not I386_CPU)
1332 */
1333ALTENTRY(suibyte)
1334ENTRY(subyte)
b7c628e4
MD
1335 movl _curthread,%ecx
1336 movl TD_PCB(%ecx),%ecx
984263bc
MD
1337 movl $fusufault,PCB_ONFAULT(%ecx)
1338 movl 4(%esp),%edx
1339
1340#if defined(I386_CPU)
1341
1342#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1343 cmpl $CPUCLASS_386,_cpu_class
1344 jne 2f
1345#endif /* I486_CPU || I586_CPU || I686_CPU */
1346
1347 movl %edx,%eax
1348 shrl $IDXSHIFT,%edx
1349 andb $0xfc,%dl
1350
1351 leal _PTmap(%edx),%ecx
1352 shrl $IDXSHIFT,%ecx
1353 andb $0xfc,%cl
1354 testb $PG_V,_PTmap(%ecx) /* PTE page must be valid */
1355 je 4f
1356 movb _PTmap(%edx),%dl
1357 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1358 cmpb $PG_V|PG_RW|PG_U,%dl
1359 je 1f
1360
13614:
1362 /* simulate a trap */
1363 pushl %eax
1364 call _trapwrite
1365 popl %edx /* remove junk parameter from stack */
1366 testl %eax,%eax
1367 jnz fusufault
13681:
1369 movl 4(%esp),%edx
1370#endif
1371
13722:
1373 cmpl $VM_MAXUSER_ADDRESS-1,%edx /* verify address validity */
1374 ja fusufault
1375
1376 movb 8(%esp),%al
1377 movb %al,(%edx)
1378 xorl %eax,%eax
b7c628e4
MD
1379 movl _curthread,%ecx /* restore trashed register */
1380 movl TD_PCB(%ecx),%ecx
984263bc
MD
1381 movl %eax,PCB_ONFAULT(%ecx)
1382 ret
1383
1384/*
1385 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
1386 *
1387 * copy a string from from to to, stop when a 0 character is reached.
1388 * return ENAMETOOLONG if string is longer than maxlen, and
1389 * EFAULT on protection violations. If lencopied is non-zero,
1390 * return the actual length in *lencopied.
1391 */
1392ENTRY(copyinstr)
1393 pushl %esi
1394 pushl %edi
b7c628e4
MD
1395 movl _curthread,%ecx
1396 movl TD_PCB(%ecx),%ecx
984263bc
MD
1397 movl $cpystrflt,PCB_ONFAULT(%ecx)
1398
1399 movl 12(%esp),%esi /* %esi = from */
1400 movl 16(%esp),%edi /* %edi = to */
1401 movl 20(%esp),%edx /* %edx = maxlen */
1402
1403 movl $VM_MAXUSER_ADDRESS,%eax
1404
1405 /* make sure 'from' is within bounds */
1406 subl %esi,%eax
1407 jbe cpystrflt
1408
1409 /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1410 cmpl %edx,%eax
1411 jae 1f
1412 movl %eax,%edx
1413 movl %eax,20(%esp)
14141:
1415 incl %edx
1416 cld
1417
14182:
1419 decl %edx
1420 jz 3f
1421
1422 lodsb
1423 stosb
1424 orb %al,%al
1425 jnz 2b
1426
1427 /* Success -- 0 byte reached */
1428 decl %edx
1429 xorl %eax,%eax
1430 jmp cpystrflt_x
14313:
1432 /* edx is zero - return ENAMETOOLONG or EFAULT */
1433 cmpl $VM_MAXUSER_ADDRESS,%esi
1434 jae cpystrflt
14354:
1436 movl $ENAMETOOLONG,%eax
1437 jmp cpystrflt_x
1438
1439cpystrflt:
1440 movl $EFAULT,%eax
1441
1442cpystrflt_x:
1443 /* set *lencopied and return %eax */
b7c628e4
MD
1444 movl _curthread,%ecx
1445 movl TD_PCB(%ecx),%ecx
984263bc
MD
1446 movl $0,PCB_ONFAULT(%ecx)
1447 movl 20(%esp),%ecx
1448 subl %edx,%ecx
1449 movl 24(%esp),%edx
1450 testl %edx,%edx
1451 jz 1f
1452 movl %ecx,(%edx)
14531:
1454 popl %edi
1455 popl %esi
1456 ret
1457
1458
1459/*
1460 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
1461 */
1462ENTRY(copystr)
1463 pushl %esi
1464 pushl %edi
1465
1466 movl 12(%esp),%esi /* %esi = from */
1467 movl 16(%esp),%edi /* %edi = to */
1468 movl 20(%esp),%edx /* %edx = maxlen */
1469 incl %edx
1470 cld
14711:
1472 decl %edx
1473 jz 4f
1474 lodsb
1475 stosb
1476 orb %al,%al
1477 jnz 1b
1478
1479 /* Success -- 0 byte reached */
1480 decl %edx
1481 xorl %eax,%eax
1482 jmp 6f
14834:
1484 /* edx is zero -- return ENAMETOOLONG */
1485 movl $ENAMETOOLONG,%eax
1486
14876:
1488 /* set *lencopied and return %eax */
1489 movl 20(%esp),%ecx
1490 subl %edx,%ecx
1491 movl 24(%esp),%edx
1492 testl %edx,%edx
1493 jz 7f
1494 movl %ecx,(%edx)
14957:
1496 popl %edi
1497 popl %esi
1498 ret
1499
1500ENTRY(bcmp)
1501 pushl %edi
1502 pushl %esi
1503 movl 12(%esp),%edi
1504 movl 16(%esp),%esi
1505 movl 20(%esp),%edx
1506 xorl %eax,%eax
1507
1508 movl %edx,%ecx
1509 shrl $2,%ecx
1510 cld /* compare forwards */
1511 repe
1512 cmpsl
1513 jne 1f
1514
1515 movl %edx,%ecx
1516 andl $3,%ecx
1517 repe
1518 cmpsb
1519 je 2f
15201:
1521 incl %eax
15222:
1523 popl %esi
1524 popl %edi
1525 ret
1526
1527
1528/*
1529 * Handling of special 386 registers and descriptor tables etc
1530 */
1531/* void lgdt(struct region_descriptor *rdp); */
1532ENTRY(lgdt)
1533 /* reload the descriptor table */
1534 movl 4(%esp),%eax
1535 lgdt (%eax)
1536
1537 /* flush the prefetch q */
1538 jmp 1f
1539 nop
15401:
1541 /* reload "stale" selectors */
1542 movl $KDSEL,%eax
1543 mov %ax,%ds
1544 mov %ax,%es
1545 mov %ax,%gs
1546 mov %ax,%ss
984263bc 1547 movl $KPSEL,%eax
984263bc
MD
1548 mov %ax,%fs
1549
1550 /* reload code selector by turning return into intersegmental return */
1551 movl (%esp),%eax
1552 pushl %eax
1553 movl $KCSEL,4(%esp)
1554 lret
1555
1556/*
1557 * void lidt(struct region_descriptor *rdp);
1558 */
1559ENTRY(lidt)
1560 movl 4(%esp),%eax
1561 lidt (%eax)
1562 ret
1563
1564/*
1565 * void lldt(u_short sel)
1566 */
1567ENTRY(lldt)
1568 lldt 4(%esp)
1569 ret
1570
1571/*
1572 * void ltr(u_short sel)
1573 */
1574ENTRY(ltr)
1575 ltr 4(%esp)
1576 ret
1577
1578/* ssdtosd(*ssdp,*sdp) */
1579ENTRY(ssdtosd)
1580 pushl %ebx
1581 movl 8(%esp),%ecx
1582 movl 8(%ecx),%ebx
1583 shll $16,%ebx
1584 movl (%ecx),%edx
1585 roll $16,%edx
1586 movb %dh,%bl
1587 movb %dl,%bh
1588 rorl $8,%ebx
1589 movl 4(%ecx),%eax
1590 movw %ax,%dx
1591 andl $0xf0000,%eax
1592 orl %eax,%ebx
1593 movl 12(%esp),%ecx
1594 movl %edx,(%ecx)
1595 movl %ebx,4(%ecx)
1596 popl %ebx
1597 ret
1598
1599/* load_cr0(cr0) */
1600ENTRY(load_cr0)
1601 movl 4(%esp),%eax
1602 movl %eax,%cr0
1603 ret
1604
1605/* rcr0() */
1606ENTRY(rcr0)
1607 movl %cr0,%eax
1608 ret
1609
1610/* rcr3() */
1611ENTRY(rcr3)
1612 movl %cr3,%eax
1613 ret
1614
1615/* void load_cr3(caddr_t cr3) */
1616ENTRY(load_cr3)
1617#if defined(SWTCH_OPTIM_STATS)
1618 incl _tlb_flush_count
1619#endif
1620 movl 4(%esp),%eax
1621 movl %eax,%cr3
1622 ret
1623
1624/* rcr4() */
1625ENTRY(rcr4)
1626 movl %cr4,%eax
1627 ret
1628
1629/* void load_cr4(caddr_t cr4) */
1630ENTRY(load_cr4)
1631 movl 4(%esp),%eax
1632 movl %eax,%cr4
1633 ret
1634
1635/* void reset_dbregs() */
1636ENTRY(reset_dbregs)
1637 movl $0,%eax
1638 movl %eax,%dr7 /* disable all breapoints first */
1639 movl %eax,%dr0
1640 movl %eax,%dr1
1641 movl %eax,%dr2
1642 movl %eax,%dr3
1643 movl %eax,%dr6
1644 ret
1645
1646/*****************************************************************************/
1647/* setjump, longjump */
1648/*****************************************************************************/
1649
1650ENTRY(setjmp)
1651 movl 4(%esp),%eax
1652 movl %ebx,(%eax) /* save ebx */
1653 movl %esp,4(%eax) /* save esp */
1654 movl %ebp,8(%eax) /* save ebp */
1655 movl %esi,12(%eax) /* save esi */
1656 movl %edi,16(%eax) /* save edi */
1657 movl (%esp),%edx /* get rta */
1658 movl %edx,20(%eax) /* save eip */
1659 xorl %eax,%eax /* return(0); */
1660 ret
1661
1662ENTRY(longjmp)
1663 movl 4(%esp),%eax
1664 movl (%eax),%ebx /* restore ebx */
1665 movl 4(%eax),%esp /* restore esp */
1666 movl 8(%eax),%ebp /* restore ebp */
1667 movl 12(%eax),%esi /* restore esi */
1668 movl 16(%eax),%edi /* restore edi */
1669 movl 20(%eax),%edx /* get rta */
1670 movl %edx,(%esp) /* put in return frame */
1671 xorl %eax,%eax /* return(1); */
1672 incl %eax
1673 ret
1674
1675/*
1676 * Support for BB-profiling (gcc -a). The kernbb program will extract
1677 * the data from the kernel.
1678 */
1679
1680 .data
1681 ALIGN_DATA
1682 .globl bbhead
1683bbhead:
1684 .long 0
1685
1686 .text
1687NON_GPROF_ENTRY(__bb_init_func)
1688 movl 4(%esp),%eax
1689 movl $1,(%eax)
1690 movl bbhead,%edx
1691 movl %edx,16(%eax)
1692 movl %eax,bbhead
1693 .byte 0xc3 /* avoid macro for `ret' */