Add mem1 and mem2 .... memory copying and zeroing test suites, making it
[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 $
6f381f08 34 * $DragonFly: src/sys/platform/pc32/i386/support.s,v 1.10 2004/04/03 08:21:16 dillon Exp $
984263bc
MD
35 */
36
1f2de5d4 37#include "use_npx.h"
984263bc
MD
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
2954c92f
MD
49 .globl bcopy_vector
50bcopy_vector:
51 .long generic_bcopy
52 .globl bzero
53bzero:
54 .long generic_bzero
55 .globl copyin_vector
56copyin_vector:
57 .long generic_copyin
58 .globl copyout_vector
59copyout_vector:
60 .long generic_copyout
61 .globl ovbcopy_vector
62ovbcopy_vector:
63 .long generic_bcopy
984263bc
MD
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 */
2954c92f 245 cmpl $0,PCPU(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
2954c92f 297 cmpl $0,PCPU(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
2954c92f 432 jmp *bcopy_vector
984263bc
MD
433
434ENTRY(ovbcopy)
435 MEXITCOUNT
2954c92f 436 jmp *ovbcopy_vector
984263bc
MD
437
438/*
439 * generic_bcopy(src, dst, cnt)
440 * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
441 */
442ENTRY(generic_bcopy)
6f381f08
MD
443 pushl %ebp /* debugging */
444 movl %esp,%ebp
984263bc
MD
445 pushl %esi
446 pushl %edi
6f381f08
MD
447 movl 16(%esp),%esi
448 movl 20(%esp),%edi
449 movl 24(%esp),%ecx
984263bc
MD
450
451 movl %edi,%eax
452 subl %esi,%eax
453 cmpl %ecx,%eax /* overlapping && src < dst? */
454 jb 1f
455
456 shrl $2,%ecx /* copy by 32-bit words */
457 cld /* nope, copy forwards */
458 rep
459 movsl
6f381f08 460 movl 24(%esp),%ecx
984263bc
MD
461 andl $3,%ecx /* any bytes left? */
462 rep
463 movsb
464 popl %edi
465 popl %esi
6f381f08 466 popl %ebp
984263bc
MD
467 ret
468
469 ALIGN_TEXT
4701:
471 addl %ecx,%edi /* copy backwards */
472 addl %ecx,%esi
473 decl %edi
474 decl %esi
475 andl $3,%ecx /* any fractional bytes? */
476 std
477 rep
478 movsb
6f381f08 479 movl 24(%esp),%ecx /* copy remainder by 32-bit words */
984263bc
MD
480 shrl $2,%ecx
481 subl $3,%esi
482 subl $3,%edi
483 rep
484 movsl
485 popl %edi
486 popl %esi
6f381f08 487 popl %ebp
984263bc
MD
488 cld
489 ret
490
491#if defined(I586_CPU) && NNPX > 0
492ENTRY(i586_bcopy)
493 pushl %esi
494 pushl %edi
495 movl 12(%esp),%esi
496 movl 16(%esp),%edi
497 movl 20(%esp),%ecx
498
499 movl %edi,%eax
500 subl %esi,%eax
501 cmpl %ecx,%eax /* overlapping && src < dst? */
502 jb 1f
503
504 cmpl $1024,%ecx
505 jb small_i586_bcopy
506
507 sarb $1,kernel_fpu_lock
508 jc small_i586_bcopy
2954c92f 509 cmpl $0,PCPU(npxthread)
984263bc
MD
510 je i586_bc1
511 smsw %dx
512 clts
513 subl $108,%esp
514 fnsave 0(%esp)
515 jmp 4f
516
517i586_bc1:
518 smsw %dx
519 clts
520 fninit /* XXX should avoid needing this */
521
522 ALIGN_TEXT
5234:
524 pushl %ecx
525#define DCACHE_SIZE 8192
526 cmpl $(DCACHE_SIZE-512)/2,%ecx
527 jbe 2f
528 movl $(DCACHE_SIZE-512)/2,%ecx
5292:
530 subl %ecx,0(%esp)
531 cmpl $256,%ecx
532 jb 5f /* XXX should prefetch if %ecx >= 32 */
533 pushl %esi
534 pushl %ecx
535 ALIGN_TEXT
5363:
537 movl 0(%esi),%eax
538 movl 32(%esi),%eax
539 movl 64(%esi),%eax
540 movl 96(%esi),%eax
541 movl 128(%esi),%eax
542 movl 160(%esi),%eax
543 movl 192(%esi),%eax
544 movl 224(%esi),%eax
545 addl $256,%esi
546 subl $256,%ecx
547 cmpl $256,%ecx
548 jae 3b
549 popl %ecx
550 popl %esi
5515:
552 ALIGN_TEXT
553large_i586_bcopy_loop:
554 fildq 0(%esi)
555 fildq 8(%esi)
556 fildq 16(%esi)
557 fildq 24(%esi)
558 fildq 32(%esi)
559 fildq 40(%esi)
560 fildq 48(%esi)
561 fildq 56(%esi)
562 fistpq 56(%edi)
563 fistpq 48(%edi)
564 fistpq 40(%edi)
565 fistpq 32(%edi)
566 fistpq 24(%edi)
567 fistpq 16(%edi)
568 fistpq 8(%edi)
569 fistpq 0(%edi)
570 addl $64,%esi
571 addl $64,%edi
572 subl $64,%ecx
573 cmpl $64,%ecx
574 jae large_i586_bcopy_loop
575 popl %eax
576 addl %eax,%ecx
577 cmpl $64,%ecx
578 jae 4b
579
2954c92f 580 cmpl $0,PCPU(npxthread)
984263bc
MD
581 je i586_bc2
582 frstor 0(%esp)
583 addl $108,%esp
584i586_bc2:
585 lmsw %dx
586 movb $0xfe,kernel_fpu_lock
587
588/*
589 * This is a duplicate of the main part of generic_bcopy. See the comments
590 * there. Jumping into generic_bcopy would cost a whole 0-1 cycles and
591 * would mess up high resolution profiling.
592 */
593 ALIGN_TEXT
594small_i586_bcopy:
595 shrl $2,%ecx
596 cld
597 rep
598 movsl
599 movl 20(%esp),%ecx
600 andl $3,%ecx
601 rep
602 movsb
603 popl %edi
604 popl %esi
605 ret
606
607 ALIGN_TEXT
6081:
609 addl %ecx,%edi
610 addl %ecx,%esi
611 decl %edi
612 decl %esi
613 andl $3,%ecx
614 std
615 rep
616 movsb
617 movl 20(%esp),%ecx
618 shrl $2,%ecx
619 subl $3,%esi
620 subl $3,%edi
621 rep
622 movsl
623 popl %edi
624 popl %esi
625 cld
626 ret
627#endif /* I586_CPU && NNPX > 0 */
628
629/*
630 * Note: memcpy does not support overlapping copies
631 */
632ENTRY(memcpy)
633 pushl %edi
634 pushl %esi
635 movl 12(%esp),%edi
636 movl 16(%esp),%esi
637 movl 20(%esp),%ecx
638 movl %edi,%eax
639 shrl $2,%ecx /* copy by 32-bit words */
640 cld /* nope, copy forwards */
641 rep
642 movsl
643 movl 20(%esp),%ecx
644 andl $3,%ecx /* any bytes left? */
645 rep
646 movsb
647 popl %esi
648 popl %edi
649 ret
650
651
652/*****************************************************************************/
653/* copyout and fubyte family */
654/*****************************************************************************/
655/*
656 * Access user memory from inside the kernel. These routines and possibly
657 * the math- and DOS emulators should be the only places that do this.
658 *
659 * We have to access the memory with user's permissions, so use a segment
660 * selector with RPL 3. For writes to user space we have to additionally
661 * check the PTE for write permission, because the 386 does not check
662 * write permissions when we are executing with EPL 0. The 486 does check
663 * this if the WP bit is set in CR0, so we can use a simpler version here.
664 *
665 * These routines set curpcb->onfault for the time they execute. When a
666 * protection violation occurs inside the functions, the trap handler
667 * returns to *curpcb->onfault instead of the function.
668 */
669
670/*
671 * copyout(from_kernel, to_user, len) - MP SAFE (if not I386_CPU)
672 */
673ENTRY(copyout)
674 MEXITCOUNT
2954c92f 675 jmp *copyout_vector
984263bc
MD
676
677ENTRY(generic_copyout)
2954c92f 678 movl PCPU(curthread),%eax
b7c628e4 679 movl TD_PCB(%eax),%eax
984263bc
MD
680 movl $copyout_fault,PCB_ONFAULT(%eax)
681 pushl %esi
682 pushl %edi
683 pushl %ebx
684 movl 16(%esp),%esi
685 movl 20(%esp),%edi
686 movl 24(%esp),%ebx
687 testl %ebx,%ebx /* anything to do? */
688 jz done_copyout
689
690 /*
691 * Check explicitly for non-user addresses. If 486 write protection
692 * is being used, this check is essential because we are in kernel
693 * mode so the h/w does not provide any protection against writing
694 * kernel addresses.
695 */
696
697 /*
698 * First, prevent address wrapping.
699 */
700 movl %edi,%eax
701 addl %ebx,%eax
702 jc copyout_fault
703/*
704 * XXX STOP USING VM_MAXUSER_ADDRESS.
705 * It is an end address, not a max, so every time it is used correctly it
706 * looks like there is an off by one error, and of course it caused an off
707 * by one error in several places.
708 */
709 cmpl $VM_MAXUSER_ADDRESS,%eax
710 ja copyout_fault
711
712#if defined(I386_CPU)
713
714#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
e38b98c0 715 cmpl $CPUCLASS_386,cpu_class
984263bc
MD
716 jne 3f
717#endif
718/*
719 * We have to check each PTE for user write permission.
720 * The checking may cause a page fault, so it is important to set
721 * up everything for return via copyout_fault before here.
722 */
723 /* compute number of pages */
724 movl %edi,%ecx
725 andl $PAGE_MASK,%ecx
726 addl %ebx,%ecx
727 decl %ecx
728 shrl $IDXSHIFT+2,%ecx
729 incl %ecx
730
731 /* compute PTE offset for start address */
732 movl %edi,%edx
733 shrl $IDXSHIFT,%edx
734 andb $0xfc,%dl
735
7361:
737 /* check PTE for each page */
2954c92f 738 leal PTmap(%edx),%eax
984263bc
MD
739 shrl $IDXSHIFT,%eax
740 andb $0xfc,%al
2954c92f 741 testb $PG_V,PTmap(%eax) /* PTE page must be valid */
984263bc 742 je 4f
2954c92f 743 movb PTmap(%edx),%al
984263bc
MD
744 andb $PG_V|PG_RW|PG_U,%al /* page must be valid and user writable */
745 cmpb $PG_V|PG_RW|PG_U,%al
746 je 2f
747
7484:
749 /* simulate a trap */
750 pushl %edx
751 pushl %ecx
752 shll $IDXSHIFT,%edx
753 pushl %edx
2954c92f 754 call trapwrite /* trapwrite(addr) */
984263bc
MD
755 popl %edx
756 popl %ecx
757 popl %edx
758
759 testl %eax,%eax /* if not ok, return EFAULT */
760 jnz copyout_fault
761
7622:
763 addl $4,%edx
764 decl %ecx
765 jnz 1b /* check next page */
766#endif /* I386_CPU */
767
768 /* bcopy(%esi, %edi, %ebx) */
7693:
770 movl %ebx,%ecx
771
772#if defined(I586_CPU) && NNPX > 0
773 ALIGN_TEXT
774slow_copyout:
775#endif
776 shrl $2,%ecx
777 cld
778 rep
779 movsl
780 movb %bl,%cl
781 andb $3,%cl
782 rep
783 movsb
784
785done_copyout:
786 popl %ebx
787 popl %edi
788 popl %esi
789 xorl %eax,%eax
2954c92f 790 movl PCPU(curthread),%edx
b7c628e4 791 movl TD_PCB(%edx),%edx
984263bc
MD
792 movl %eax,PCB_ONFAULT(%edx)
793 ret
794
795 ALIGN_TEXT
796copyout_fault:
797 popl %ebx
798 popl %edi
799 popl %esi
2954c92f 800 movl PCPU(curthread),%edx
b7c628e4 801 movl TD_PCB(%edx),%edx
984263bc
MD
802 movl $0,PCB_ONFAULT(%edx)
803 movl $EFAULT,%eax
804 ret
805
806#if defined(I586_CPU) && NNPX > 0
807ENTRY(i586_copyout)
808 /*
809 * Duplicated from generic_copyout. Could be done a bit better.
810 */
2954c92f 811 movl PCPU(curthread),%eax
b7c628e4 812 movl TD_PCB(%eax),%eax
984263bc
MD
813 movl $copyout_fault,PCB_ONFAULT(%eax)
814 pushl %esi
815 pushl %edi
816 pushl %ebx
817 movl 16(%esp),%esi
818 movl 20(%esp),%edi
819 movl 24(%esp),%ebx
820 testl %ebx,%ebx /* anything to do? */
821 jz done_copyout
822
823 /*
824 * Check explicitly for non-user addresses. If 486 write protection
825 * is being used, this check is essential because we are in kernel
826 * mode so the h/w does not provide any protection against writing
827 * kernel addresses.
828 */
829
830 /*
831 * First, prevent address wrapping.
832 */
833 movl %edi,%eax
834 addl %ebx,%eax
835 jc copyout_fault
836/*
837 * XXX STOP USING VM_MAXUSER_ADDRESS.
838 * It is an end address, not a max, so every time it is used correctly it
839 * looks like there is an off by one error, and of course it caused an off
840 * by one error in several places.
841 */
842 cmpl $VM_MAXUSER_ADDRESS,%eax
843 ja copyout_fault
844
845 /* bcopy(%esi, %edi, %ebx) */
8463:
847 movl %ebx,%ecx
848 /*
849 * End of duplicated code.
850 */
851
852 cmpl $1024,%ecx
853 jb slow_copyout
854
855 pushl %ecx
2954c92f 856 call fastmove
984263bc
MD
857 addl $4,%esp
858 jmp done_copyout
859#endif /* I586_CPU && NNPX > 0 */
860
861/*
862 * copyin(from_user, to_kernel, len) - MP SAFE
863 */
864ENTRY(copyin)
865 MEXITCOUNT
2954c92f 866 jmp *copyin_vector
984263bc
MD
867
868ENTRY(generic_copyin)
2954c92f 869 movl PCPU(curthread),%eax
b7c628e4 870 movl TD_PCB(%eax),%eax
984263bc
MD
871 movl $copyin_fault,PCB_ONFAULT(%eax)
872 pushl %esi
873 pushl %edi
874 movl 12(%esp),%esi /* caddr_t from */
875 movl 16(%esp),%edi /* caddr_t to */
876 movl 20(%esp),%ecx /* size_t len */
877
878 /*
879 * make sure address is valid
880 */
881 movl %esi,%edx
882 addl %ecx,%edx
883 jc copyin_fault
884 cmpl $VM_MAXUSER_ADDRESS,%edx
885 ja copyin_fault
886
887#if defined(I586_CPU) && NNPX > 0
888 ALIGN_TEXT
889slow_copyin:
890#endif
891 movb %cl,%al
892 shrl $2,%ecx /* copy longword-wise */
893 cld
894 rep
895 movsl
896 movb %al,%cl
897 andb $3,%cl /* copy remaining bytes */
898 rep
899 movsb
900
901#if defined(I586_CPU) && NNPX > 0
902 ALIGN_TEXT
903done_copyin:
904#endif
905 popl %edi
906 popl %esi
907 xorl %eax,%eax
2954c92f 908 movl PCPU(curthread),%edx
b7c628e4 909 movl TD_PCB(%edx),%edx
984263bc
MD
910 movl %eax,PCB_ONFAULT(%edx)
911 ret
912
913 ALIGN_TEXT
914copyin_fault:
915 popl %edi
916 popl %esi
2954c92f 917 movl PCPU(curthread),%edx
b7c628e4 918 movl TD_PCB(%edx),%edx
984263bc
MD
919 movl $0,PCB_ONFAULT(%edx)
920 movl $EFAULT,%eax
921 ret
922
923#if defined(I586_CPU) && NNPX > 0
924ENTRY(i586_copyin)
925 /*
926 * Duplicated from generic_copyin. Could be done a bit better.
927 */
2954c92f 928 movl PCPU(curthread),%eax
b7c628e4 929 movl TD_PCB(%eax),%eax
984263bc
MD
930 movl $copyin_fault,PCB_ONFAULT(%eax)
931 pushl %esi
932 pushl %edi
933 movl 12(%esp),%esi /* caddr_t from */
934 movl 16(%esp),%edi /* caddr_t to */
935 movl 20(%esp),%ecx /* size_t len */
936
937 /*
938 * make sure address is valid
939 */
940 movl %esi,%edx
941 addl %ecx,%edx
942 jc copyin_fault
943 cmpl $VM_MAXUSER_ADDRESS,%edx
944 ja copyin_fault
945 /*
946 * End of duplicated code.
947 */
948
949 cmpl $1024,%ecx
950 jb slow_copyin
951
952 pushl %ebx /* XXX prepare for fastmove_fault */
953 pushl %ecx
2954c92f 954 call fastmove
984263bc
MD
955 addl $8,%esp
956 jmp done_copyin
957#endif /* I586_CPU && NNPX > 0 */
958
959#if defined(I586_CPU) && NNPX > 0
960/* fastmove(src, dst, len)
961 src in %esi
962 dst in %edi
963 len in %ecx XXX changed to on stack for profiling
964 uses %eax and %edx for tmp. storage
965 */
966/* XXX use ENTRY() to get profiling. fastmove() is actually a non-entry. */
967ENTRY(fastmove)
968 pushl %ebp
969 movl %esp,%ebp
970 subl $PCB_SAVE87_SIZE+3*4,%esp
971
972 movl 8(%ebp),%ecx
973 cmpl $63,%ecx
974 jbe fastmove_tail
975
976 testl $7,%esi /* check if src addr is multiple of 8 */
977 jnz fastmove_tail
978
979 testl $7,%edi /* check if dst addr is multiple of 8 */
980 jnz fastmove_tail
981
af0bff84 982/* if (npxthread != NULL) { */
2954c92f 983 cmpl $0,PCPU(npxthread)
984263bc
MD
984 je 6f
985/* fnsave(&curpcb->pcb_savefpu); */
2954c92f 986 movl PCPU(curthread),%eax
b7c628e4 987 movl TD_PCB(%eax),%eax
984263bc 988 fnsave PCB_SAVEFPU(%eax)
af0bff84 989/* npxthread = NULL; */
2954c92f 990 movl $0,PCPU(npxthread)
984263bc
MD
991/* } */
9926:
993/* now we own the FPU. */
994
995/*
996 * The process' FP state is saved in the pcb, but if we get
997 * switched, the cpu_switch() will store our FP state in the
998 * pcb. It should be possible to avoid all the copying for
999 * this, e.g., by setting a flag to tell cpu_switch() to
1000 * save the state somewhere else.
1001 */
1002/* tmp = curpcb->pcb_savefpu; */
1003 movl %ecx,-12(%ebp)
1004 movl %esi,-8(%ebp)
1005 movl %edi,-4(%ebp)
1006 movl %esp,%edi
2954c92f 1007 movl PCPU(curthread),%esi
b7c628e4 1008 movl TD_PCB(%esi),%esi
984263bc
MD
1009 addl $PCB_SAVEFPU,%esi
1010 cld
1011 movl $PCB_SAVE87_SIZE>>2,%ecx
1012 rep
1013 movsl
1014 movl -12(%ebp),%ecx
1015 movl -8(%ebp),%esi
1016 movl -4(%ebp),%edi
1017/* stop_emulating(); */
1018 clts
af0bff84 1019/* npxthread = curthread; */
2954c92f
MD
1020 movl PCPU(curthread),%eax
1021 movl %eax,PCPU(npxthread)
1022 movl PCPU(curthread),%eax
b7c628e4 1023 movl TD_PCB(%eax),%eax
984263bc
MD
1024 movl $fastmove_fault,PCB_ONFAULT(%eax)
10254:
1026 movl %ecx,-12(%ebp)
1027 cmpl $1792,%ecx
1028 jbe 2f
1029 movl $1792,%ecx
10302:
1031 subl %ecx,-12(%ebp)
1032 cmpl $256,%ecx
1033 jb 5f
1034 movl %ecx,-8(%ebp)
1035 movl %esi,-4(%ebp)
1036 ALIGN_TEXT
10373:
1038 movl 0(%esi),%eax
1039 movl 32(%esi),%eax
1040 movl 64(%esi),%eax
1041 movl 96(%esi),%eax
1042 movl 128(%esi),%eax
1043 movl 160(%esi),%eax
1044 movl 192(%esi),%eax
1045 movl 224(%esi),%eax
1046 addl $256,%esi
1047 subl $256,%ecx
1048 cmpl $256,%ecx
1049 jae 3b
1050 movl -8(%ebp),%ecx
1051 movl -4(%ebp),%esi
10525:
1053 ALIGN_TEXT
1054fastmove_loop:
1055 fildq 0(%esi)
1056 fildq 8(%esi)
1057 fildq 16(%esi)
1058 fildq 24(%esi)
1059 fildq 32(%esi)
1060 fildq 40(%esi)
1061 fildq 48(%esi)
1062 fildq 56(%esi)
1063 fistpq 56(%edi)
1064 fistpq 48(%edi)
1065 fistpq 40(%edi)
1066 fistpq 32(%edi)
1067 fistpq 24(%edi)
1068 fistpq 16(%edi)
1069 fistpq 8(%edi)
1070 fistpq 0(%edi)
1071 addl $-64,%ecx
1072 addl $64,%esi
1073 addl $64,%edi
1074 cmpl $63,%ecx
1075 ja fastmove_loop
1076 movl -12(%ebp),%eax
1077 addl %eax,%ecx
1078 cmpl $64,%ecx
1079 jae 4b
1080
1081/* curpcb->pcb_savefpu = tmp; */
1082 movl %ecx,-12(%ebp)
1083 movl %esi,-8(%ebp)
1084 movl %edi,-4(%ebp)
2954c92f 1085 movl PCPU(curthread),%edi
b7c628e4 1086 movl TD_PCB(%edi),%edi
984263bc
MD
1087 addl $PCB_SAVEFPU,%edi
1088 movl %esp,%esi
1089 cld
1090 movl $PCB_SAVE87_SIZE>>2,%ecx
1091 rep
1092 movsl
1093 movl -12(%ebp),%ecx
1094 movl -8(%ebp),%esi
1095 movl -4(%ebp),%edi
1096
1097/* start_emulating(); */
1098 smsw %ax
1099 orb $CR0_TS,%al
1100 lmsw %ax
af0bff84 1101/* npxthread = NULL; */
2954c92f 1102 movl $0,PCPU(npxthread)
984263bc
MD
1103
1104 ALIGN_TEXT
1105fastmove_tail:
2954c92f 1106 movl PCPU(curthread),%eax
b7c628e4 1107 movl TD_PCB(%eax),%eax
984263bc
MD
1108 movl $fastmove_tail_fault,PCB_ONFAULT(%eax)
1109
1110 movb %cl,%al
1111 shrl $2,%ecx /* copy longword-wise */
1112 cld
1113 rep
1114 movsl
1115 movb %al,%cl
1116 andb $3,%cl /* copy remaining bytes */
1117 rep
1118 movsb
1119
1120 movl %ebp,%esp
1121 popl %ebp
1122 ret
1123
1124 ALIGN_TEXT
1125fastmove_fault:
2954c92f 1126 movl PCPU(curthread),%edi
b7c628e4 1127 movl TD_PCB(%edi),%edi
984263bc
MD
1128 addl $PCB_SAVEFPU,%edi
1129 movl %esp,%esi
1130 cld
1131 movl $PCB_SAVE87_SIZE>>2,%ecx
1132 rep
1133 movsl
1134
1135 smsw %ax
1136 orb $CR0_TS,%al
1137 lmsw %ax
2954c92f 1138 movl $0,PCPU(npxthread)
984263bc
MD
1139
1140fastmove_tail_fault:
1141 movl %ebp,%esp
1142 popl %ebp
1143 addl $8,%esp
1144 popl %ebx
1145 popl %edi
1146 popl %esi
2954c92f 1147 movl PCPU(curthread),%edx
b7c628e4 1148 movl TD_PCB(%edx),%edx
984263bc
MD
1149 movl $0,PCB_ONFAULT(%edx)
1150 movl $EFAULT,%eax
1151 ret
1152#endif /* I586_CPU && NNPX > 0 */
1153
1154/*
1155 * fu{byte,sword,word} - MP SAFE
1156 *
1157 * Fetch a byte (sword, word) from user memory
1158 */
1159ENTRY(fuword)
2954c92f 1160 movl PCPU(curthread),%ecx
b7c628e4 1161 movl TD_PCB(%ecx),%ecx
984263bc
MD
1162 movl $fusufault,PCB_ONFAULT(%ecx)
1163 movl 4(%esp),%edx /* from */
1164
1165 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */
1166 ja fusufault
1167
1168 movl (%edx),%eax
1169 movl $0,PCB_ONFAULT(%ecx)
1170 ret
1171
1172/*
1173 * These two routines are called from the profiling code, potentially
1174 * at interrupt time. If they fail, that's okay, good things will
1175 * happen later. Fail all the time for now - until the trap code is
1176 * able to deal with this.
1177 */
1178ALTENTRY(suswintr)
1179ENTRY(fuswintr)
1180 movl $-1,%eax
1181 ret
1182
1183/*
1184 * fusword - MP SAFE
1185 */
1186ENTRY(fusword)
2954c92f 1187 movl PCPU(curthread),%ecx
b7c628e4 1188 movl TD_PCB(%ecx),%ecx
984263bc
MD
1189 movl $fusufault,PCB_ONFAULT(%ecx)
1190 movl 4(%esp),%edx
1191
1192 cmpl $VM_MAXUSER_ADDRESS-2,%edx
1193 ja fusufault
1194
1195 movzwl (%edx),%eax
1196 movl $0,PCB_ONFAULT(%ecx)
1197 ret
1198
1199/*
1200 * fubyte - MP SAFE
1201 */
1202ENTRY(fubyte)
2954c92f 1203 movl PCPU(curthread),%ecx
b7c628e4 1204 movl TD_PCB(%ecx),%ecx
984263bc
MD
1205 movl $fusufault,PCB_ONFAULT(%ecx)
1206 movl 4(%esp),%edx
1207
1208 cmpl $VM_MAXUSER_ADDRESS-1,%edx
1209 ja fusufault
1210
1211 movzbl (%edx),%eax
1212 movl $0,PCB_ONFAULT(%ecx)
1213 ret
1214
1215 ALIGN_TEXT
1216fusufault:
2954c92f 1217 movl PCPU(curthread),%ecx
b7c628e4 1218 movl TD_PCB(%ecx),%ecx
984263bc
MD
1219 xorl %eax,%eax
1220 movl %eax,PCB_ONFAULT(%ecx)
1221 decl %eax
1222 ret
1223
1224/*
1225 * su{byte,sword,word} - MP SAFE (if not I386_CPU)
1226 *
1227 * Write a byte (word, longword) to user memory
1228 */
1229ENTRY(suword)
2954c92f 1230 movl PCPU(curthread),%ecx
b7c628e4 1231 movl TD_PCB(%ecx),%ecx
984263bc
MD
1232 movl $fusufault,PCB_ONFAULT(%ecx)
1233 movl 4(%esp),%edx
1234
1235#if defined(I386_CPU)
1236
1237#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
e38b98c0 1238 cmpl $CPUCLASS_386,cpu_class
984263bc
MD
1239 jne 2f /* we only have to set the right segment selector */
1240#endif /* I486_CPU || I586_CPU || I686_CPU */
1241
1242 /* XXX - page boundary crossing is still not handled */
1243 movl %edx,%eax
1244 shrl $IDXSHIFT,%edx
1245 andb $0xfc,%dl
1246
e38b98c0 1247 leal PTmap(%edx),%ecx
984263bc
MD
1248 shrl $IDXSHIFT,%ecx
1249 andb $0xfc,%cl
e38b98c0 1250 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
984263bc 1251 je 4f
e38b98c0 1252 movb PTmap(%edx),%dl
984263bc
MD
1253 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1254 cmpb $PG_V|PG_RW|PG_U,%dl
1255 je 1f
1256
12574:
1258 /* simulate a trap */
1259 pushl %eax
e38b98c0 1260 call trapwrite
984263bc
MD
1261 popl %edx /* remove junk parameter from stack */
1262 testl %eax,%eax
1263 jnz fusufault
12641:
1265 movl 4(%esp),%edx
1266#endif
1267
12682:
1269 cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address validity */
1270 ja fusufault
1271
1272 movl 8(%esp),%eax
1273 movl %eax,(%edx)
1274 xorl %eax,%eax
2954c92f 1275 movl PCPU(curthread),%ecx
b7c628e4 1276 movl TD_PCB(%ecx),%ecx
984263bc
MD
1277 movl %eax,PCB_ONFAULT(%ecx)
1278 ret
1279
1280/*
1281 * susword - MP SAFE (if not I386_CPU)
1282 */
1283ENTRY(susword)
2954c92f 1284 movl PCPU(curthread),%ecx
b7c628e4 1285 movl TD_PCB(%ecx),%ecx
984263bc
MD
1286 movl $fusufault,PCB_ONFAULT(%ecx)
1287 movl 4(%esp),%edx
1288
1289#if defined(I386_CPU)
1290
1291#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
e38b98c0 1292 cmpl $CPUCLASS_386,cpu_class
984263bc
MD
1293 jne 2f
1294#endif /* I486_CPU || I586_CPU || I686_CPU */
1295
1296 /* XXX - page boundary crossing is still not handled */
1297 movl %edx,%eax
1298 shrl $IDXSHIFT,%edx
1299 andb $0xfc,%dl
1300
e38b98c0 1301 leal PTmap(%edx),%ecx
984263bc
MD
1302 shrl $IDXSHIFT,%ecx
1303 andb $0xfc,%cl
e38b98c0 1304 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
984263bc 1305 je 4f
e38b98c0 1306 movb PTmap(%edx),%dl
984263bc
MD
1307 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1308 cmpb $PG_V|PG_RW|PG_U,%dl
1309 je 1f
1310
13114:
1312 /* simulate a trap */
1313 pushl %eax
e38b98c0 1314 call trapwrite
984263bc
MD
1315 popl %edx /* remove junk parameter from stack */
1316 testl %eax,%eax
1317 jnz fusufault
13181:
1319 movl 4(%esp),%edx
1320#endif
1321
13222:
1323 cmpl $VM_MAXUSER_ADDRESS-2,%edx /* verify address validity */
1324 ja fusufault
1325
1326 movw 8(%esp),%ax
1327 movw %ax,(%edx)
1328 xorl %eax,%eax
2954c92f 1329 movl PCPU(curthread),%ecx /* restore trashed register */
b7c628e4 1330 movl TD_PCB(%ecx),%ecx
984263bc
MD
1331 movl %eax,PCB_ONFAULT(%ecx)
1332 ret
1333
1334/*
1335 * su[i]byte - MP SAFE (if not I386_CPU)
1336 */
1337ALTENTRY(suibyte)
1338ENTRY(subyte)
2954c92f 1339 movl PCPU(curthread),%ecx
b7c628e4 1340 movl TD_PCB(%ecx),%ecx
984263bc
MD
1341 movl $fusufault,PCB_ONFAULT(%ecx)
1342 movl 4(%esp),%edx
1343
1344#if defined(I386_CPU)
1345
1346#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
e38b98c0 1347 cmpl $CPUCLASS_386,cpu_class
984263bc
MD
1348 jne 2f
1349#endif /* I486_CPU || I586_CPU || I686_CPU */
1350
1351 movl %edx,%eax
1352 shrl $IDXSHIFT,%edx
1353 andb $0xfc,%dl
1354
e38b98c0 1355 leal PTmap(%edx),%ecx
984263bc
MD
1356 shrl $IDXSHIFT,%ecx
1357 andb $0xfc,%cl
e38b98c0 1358 testb $PG_V,PTmap(%ecx) /* PTE page must be valid */
984263bc 1359 je 4f
e38b98c0 1360 movb PTmap(%edx),%dl
984263bc
MD
1361 andb $PG_V|PG_RW|PG_U,%dl /* page must be valid and user writable */
1362 cmpb $PG_V|PG_RW|PG_U,%dl
1363 je 1f
1364
13654:
1366 /* simulate a trap */
1367 pushl %eax
e38b98c0 1368 call trapwrite
984263bc
MD
1369 popl %edx /* remove junk parameter from stack */
1370 testl %eax,%eax
1371 jnz fusufault
13721:
1373 movl 4(%esp),%edx
1374#endif
1375
13762:
1377 cmpl $VM_MAXUSER_ADDRESS-1,%edx /* verify address validity */
1378 ja fusufault
1379
1380 movb 8(%esp),%al
1381 movb %al,(%edx)
1382 xorl %eax,%eax
2954c92f 1383 movl PCPU(curthread),%ecx /* restore trashed register */
b7c628e4 1384 movl TD_PCB(%ecx),%ecx
984263bc
MD
1385 movl %eax,PCB_ONFAULT(%ecx)
1386 ret
1387
1388/*
1389 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
1390 *
1391 * copy a string from from to to, stop when a 0 character is reached.
1392 * return ENAMETOOLONG if string is longer than maxlen, and
1393 * EFAULT on protection violations. If lencopied is non-zero,
1394 * return the actual length in *lencopied.
1395 */
1396ENTRY(copyinstr)
1397 pushl %esi
1398 pushl %edi
2954c92f 1399 movl PCPU(curthread),%ecx
b7c628e4 1400 movl TD_PCB(%ecx),%ecx
984263bc
MD
1401 movl $cpystrflt,PCB_ONFAULT(%ecx)
1402
1403 movl 12(%esp),%esi /* %esi = from */
1404 movl 16(%esp),%edi /* %edi = to */
1405 movl 20(%esp),%edx /* %edx = maxlen */
1406
1407 movl $VM_MAXUSER_ADDRESS,%eax
1408
1409 /* make sure 'from' is within bounds */
1410 subl %esi,%eax
1411 jbe cpystrflt
1412
1413 /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1414 cmpl %edx,%eax
1415 jae 1f
1416 movl %eax,%edx
1417 movl %eax,20(%esp)
14181:
1419 incl %edx
1420 cld
1421
14222:
1423 decl %edx
1424 jz 3f
1425
1426 lodsb
1427 stosb
1428 orb %al,%al
1429 jnz 2b
1430
1431 /* Success -- 0 byte reached */
1432 decl %edx
1433 xorl %eax,%eax
1434 jmp cpystrflt_x
14353:
1436 /* edx is zero - return ENAMETOOLONG or EFAULT */
1437 cmpl $VM_MAXUSER_ADDRESS,%esi
1438 jae cpystrflt
14394:
1440 movl $ENAMETOOLONG,%eax
1441 jmp cpystrflt_x
1442
1443cpystrflt:
1444 movl $EFAULT,%eax
1445
1446cpystrflt_x:
1447 /* set *lencopied and return %eax */
2954c92f 1448 movl PCPU(curthread),%ecx
b7c628e4 1449 movl TD_PCB(%ecx),%ecx
984263bc
MD
1450 movl $0,PCB_ONFAULT(%ecx)
1451 movl 20(%esp),%ecx
1452 subl %edx,%ecx
1453 movl 24(%esp),%edx
1454 testl %edx,%edx
1455 jz 1f
1456 movl %ecx,(%edx)
14571:
1458 popl %edi
1459 popl %esi
1460 ret
1461
1462
1463/*
1464 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
1465 */
1466ENTRY(copystr)
1467 pushl %esi
1468 pushl %edi
1469
1470 movl 12(%esp),%esi /* %esi = from */
1471 movl 16(%esp),%edi /* %edi = to */
1472 movl 20(%esp),%edx /* %edx = maxlen */
1473 incl %edx
1474 cld
14751:
1476 decl %edx
1477 jz 4f
1478 lodsb
1479 stosb
1480 orb %al,%al
1481 jnz 1b
1482
1483 /* Success -- 0 byte reached */
1484 decl %edx
1485 xorl %eax,%eax
1486 jmp 6f
14874:
1488 /* edx is zero -- return ENAMETOOLONG */
1489 movl $ENAMETOOLONG,%eax
1490
14916:
1492 /* set *lencopied and return %eax */
1493 movl 20(%esp),%ecx
1494 subl %edx,%ecx
1495 movl 24(%esp),%edx
1496 testl %edx,%edx
1497 jz 7f
1498 movl %ecx,(%edx)
14997:
1500 popl %edi
1501 popl %esi
1502 ret
1503
1504ENTRY(bcmp)
1505 pushl %edi
1506 pushl %esi
1507 movl 12(%esp),%edi
1508 movl 16(%esp),%esi
1509 movl 20(%esp),%edx
1510 xorl %eax,%eax
1511
1512 movl %edx,%ecx
1513 shrl $2,%ecx
1514 cld /* compare forwards */
1515 repe
1516 cmpsl
1517 jne 1f
1518
1519 movl %edx,%ecx
1520 andl $3,%ecx
1521 repe
1522 cmpsb
1523 je 2f
15241:
1525 incl %eax
15262:
1527 popl %esi
1528 popl %edi
1529 ret
1530
1531
1532/*
1533 * Handling of special 386 registers and descriptor tables etc
1534 */
1535/* void lgdt(struct region_descriptor *rdp); */
1536ENTRY(lgdt)
1537 /* reload the descriptor table */
1538 movl 4(%esp),%eax
1539 lgdt (%eax)
1540
1541 /* flush the prefetch q */
1542 jmp 1f
1543 nop
15441:
1545 /* reload "stale" selectors */
1546 movl $KDSEL,%eax
1547 mov %ax,%ds
1548 mov %ax,%es
1549 mov %ax,%gs
1550 mov %ax,%ss
984263bc 1551 movl $KPSEL,%eax
984263bc
MD
1552 mov %ax,%fs
1553
1554 /* reload code selector by turning return into intersegmental return */
1555 movl (%esp),%eax
1556 pushl %eax
1557 movl $KCSEL,4(%esp)
1558 lret
1559
1560/*
1561 * void lidt(struct region_descriptor *rdp);
1562 */
1563ENTRY(lidt)
1564 movl 4(%esp),%eax
1565 lidt (%eax)
1566 ret
1567
1568/*
1569 * void lldt(u_short sel)
1570 */
1571ENTRY(lldt)
1572 lldt 4(%esp)
1573 ret
1574
1575/*
1576 * void ltr(u_short sel)
1577 */
1578ENTRY(ltr)
1579 ltr 4(%esp)
1580 ret
1581
1582/* ssdtosd(*ssdp,*sdp) */
1583ENTRY(ssdtosd)
1584 pushl %ebx
1585 movl 8(%esp),%ecx
1586 movl 8(%ecx),%ebx
1587 shll $16,%ebx
1588 movl (%ecx),%edx
1589 roll $16,%edx
1590 movb %dh,%bl
1591 movb %dl,%bh
1592 rorl $8,%ebx
1593 movl 4(%ecx),%eax
1594 movw %ax,%dx
1595 andl $0xf0000,%eax
1596 orl %eax,%ebx
1597 movl 12(%esp),%ecx
1598 movl %edx,(%ecx)
1599 movl %ebx,4(%ecx)
1600 popl %ebx
1601 ret
1602
1603/* load_cr0(cr0) */
1604ENTRY(load_cr0)
1605 movl 4(%esp),%eax
1606 movl %eax,%cr0
1607 ret
1608
1609/* rcr0() */
1610ENTRY(rcr0)
1611 movl %cr0,%eax
1612 ret
1613
1614/* rcr3() */
1615ENTRY(rcr3)
1616 movl %cr3,%eax
1617 ret
1618
1619/* void load_cr3(caddr_t cr3) */
1620ENTRY(load_cr3)
1621#if defined(SWTCH_OPTIM_STATS)
1622 incl _tlb_flush_count
1623#endif
1624 movl 4(%esp),%eax
1625 movl %eax,%cr3
1626 ret
1627
1628/* rcr4() */
1629ENTRY(rcr4)
1630 movl %cr4,%eax
1631 ret
1632
1633/* void load_cr4(caddr_t cr4) */
1634ENTRY(load_cr4)
1635 movl 4(%esp),%eax
1636 movl %eax,%cr4
1637 ret
1638
1639/* void reset_dbregs() */
1640ENTRY(reset_dbregs)
1641 movl $0,%eax
1642 movl %eax,%dr7 /* disable all breapoints first */
1643 movl %eax,%dr0
1644 movl %eax,%dr1
1645 movl %eax,%dr2
1646 movl %eax,%dr3
1647 movl %eax,%dr6
1648 ret
1649
1650/*****************************************************************************/
1651/* setjump, longjump */
1652/*****************************************************************************/
1653
1654ENTRY(setjmp)
1655 movl 4(%esp),%eax
1656 movl %ebx,(%eax) /* save ebx */
1657 movl %esp,4(%eax) /* save esp */
1658 movl %ebp,8(%eax) /* save ebp */
1659 movl %esi,12(%eax) /* save esi */
1660 movl %edi,16(%eax) /* save edi */
1661 movl (%esp),%edx /* get rta */
1662 movl %edx,20(%eax) /* save eip */
1663 xorl %eax,%eax /* return(0); */
1664 ret
1665
1666ENTRY(longjmp)
1667 movl 4(%esp),%eax
1668 movl (%eax),%ebx /* restore ebx */
1669 movl 4(%eax),%esp /* restore esp */
1670 movl 8(%eax),%ebp /* restore ebp */
1671 movl 12(%eax),%esi /* restore esi */
1672 movl 16(%eax),%edi /* restore edi */
1673 movl 20(%eax),%edx /* get rta */
1674 movl %edx,(%esp) /* put in return frame */
1675 xorl %eax,%eax /* return(1); */
1676 incl %eax
1677 ret
1678
1679/*
1680 * Support for BB-profiling (gcc -a). The kernbb program will extract
1681 * the data from the kernel.
1682 */
1683
1684 .data
1685 ALIGN_DATA
1686 .globl bbhead
1687bbhead:
1688 .long 0
1689
1690 .text
1691NON_GPROF_ENTRY(__bb_init_func)
1692 movl 4(%esp),%eax
1693 movl $1,(%eax)
1694 movl bbhead,%edx
1695 movl %edx,16(%eax)
1696 movl %eax,bbhead
1697 .byte 0xc3 /* avoid macro for `ret' */