Diff for /src/sys/i386/i386/Attic/support.s between versions 1.10 and 1.11

version 1.10, 2004/04/03 08:21:16 version 1.11, 2004/04/29 17:24:58
Line 46 Line 46
 #define IDXSHIFT        10  #define IDXSHIFT        10
   
         .data          .data
   
           .globl  memcpy_vector
   memcpy_vector:
           .long   asm_generic_memcpy
   
         .globl  bcopy_vector          .globl  bcopy_vector
 bcopy_vector:  bcopy_vector:
        .long   generic_bcopy        .long   asm_generic_bcopy
 
         .globl  bzero          .globl  bzero
 bzero:  bzero:
         .long   generic_bzero          .long   generic_bzero
        .globl  copyin_vector
copyin_vector: 
        .long   generic_copyin 
        .globl  copyout_vector 
copyout_vector: 
        .long   generic_copyout 
         .globl  ovbcopy_vector          .globl  ovbcopy_vector
 ovbcopy_vector:  ovbcopy_vector:
        .long   generic_bcopy        .long   asm_generic_bcopy
#if defined(I586_CPU) && NNPX > 0 
kernel_fpu_lock: 
        .byte   0xfe 
        .space  3 
#endif 
 
        .text 
 
/* 
 * bcopy family 
 * void bzero(void *buf, u_int len) 
 */ 
 
ENTRY(generic_bzero) 
        pushl   %edi 
        movl    8(%esp),%edi 
        movl    12(%esp),%ecx 
        xorl    %eax,%eax 
        shrl    $2,%ecx 
        cld 
        rep 
        stosl 
        movl    12(%esp),%ecx 
        andl    $3,%ecx 
        rep 
        stosb 
        popl    %edi 
        ret 
 
#if defined(I486_CPU) 
ENTRY(i486_bzero) 
        movl    4(%esp),%edx 
        movl    8(%esp),%ecx 
        xorl    %eax,%eax 
/* 
 * do 64 byte chunks first 
 * 
 * XXX this is probably over-unrolled at least for DX2's 
 */ 
2: 
        cmpl    $64,%ecx 
        jb      3f 
        movl    %eax,(%edx) 
        movl    %eax,4(%edx) 
        movl    %eax,8(%edx) 
        movl    %eax,12(%edx) 
        movl    %eax,16(%edx) 
        movl    %eax,20(%edx) 
        movl    %eax,24(%edx) 
        movl    %eax,28(%edx) 
        movl    %eax,32(%edx) 
        movl    %eax,36(%edx) 
        movl    %eax,40(%edx) 
        movl    %eax,44(%edx) 
        movl    %eax,48(%edx) 
        movl    %eax,52(%edx) 
        movl    %eax,56(%edx) 
        movl    %eax,60(%edx) 
        addl    $64,%edx 
        subl    $64,%ecx 
        jnz     2b 
        ret 
 
/* 
 * do 16 byte chunks 
 */ 
        SUPERALIGN_TEXT 
3: 
        cmpl    $16,%ecx 
        jb      4f 
        movl    %eax,(%edx) 
        movl    %eax,4(%edx) 
        movl    %eax,8(%edx) 
        movl    %eax,12(%edx) 
        addl    $16,%edx 
        subl    $16,%ecx 
        jnz     3b 
        ret 
 
/* 
 * do 4 byte chunks 
 */ 
        SUPERALIGN_TEXT 
4: 
        cmpl    $4,%ecx 
        jb      5f 
        movl    %eax,(%edx) 
        addl    $4,%edx 
        subl    $4,%ecx 
        jnz     4b 
        ret 
 
/* 
 * do 1 byte chunks 
 * a jump table seems to be faster than a loop or more range reductions 
 * 
 * XXX need a const section for non-text 
 */ 
        .data 
jtab: 
        .long   do0 
        .long   do1 
        .long   do2 
        .long   do3 
   
         .text          .text
         SUPERALIGN_TEXT  
 5:  
         jmp     *jtab(,%ecx,4)  
   
         SUPERALIGN_TEXT  
 do3:  
         movw    %ax,(%edx)  
         movb    %al,2(%edx)  
         ret  
   
         SUPERALIGN_TEXT  
 do2:  
         movw    %ax,(%edx)  
         ret  
   
         SUPERALIGN_TEXT  
 do1:  
         movb    %al,(%edx)  
         ret  
   
         SUPERALIGN_TEXT  
 do0:  
         ret  
 #endif  
   
 #if defined(I586_CPU) && NNPX > 0  
 ENTRY(i586_bzero)  
         movl    4(%esp),%edx  
         movl    8(%esp),%ecx  
   
         /*  
          * The FPU register method is twice as fast as the integer register  
          * method unless the target is in the L1 cache and we pre-allocate a  
          * cache line for it (then the integer register method is 4-5 times  
          * faster).  However, we never pre-allocate cache lines, since that  
          * would make the integer method 25% or more slower for the common  
          * case when the target isn't in either the L1 cache or the L2 cache.  
          * Thus we normally use the FPU register method unless the overhead  
          * would be too large.  
          */  
         cmpl    $256,%ecx       /* empirical; clts, fninit, smsw cost a lot */  
         jb      intreg_i586_bzero  
   
         /*  
          * The FPU registers may belong to an application or to fastmove()  
          * or to another invocation of bcopy() or ourself in a higher level  
          * interrupt or trap handler.  Preserving the registers is  
          * complicated since we avoid it if possible at all levels.  We  
          * want to localize the complications even when that increases them.  
          * Here the extra work involves preserving CR0_TS in TS.  
          * `npxthread != NULL' is supposed to be the condition that all the  
          * FPU resources belong to an application, but npxthread and CR0_TS  
          * aren't set atomically enough for this condition to work in  
          * interrupt handlers.  
          *  
          * Case 1: FPU registers belong to the application: we must preserve  
          * the registers if we use them, so we only use the FPU register  
          * method if the target size is large enough to amortize the extra  
          * overhead for preserving them.  CR0_TS must be preserved although  
          * it is very likely to end up as set.  
          *  
          * Case 2: FPU registers belong to fastmove(): fastmove() currently  
          * makes the registers look like they belong to an application so  
          * that cpu_switch() and savectx() don't have to know about it, so  
          * this case reduces to case 1.  
          *  
          * Case 3: FPU registers belong to the kernel: don't use the FPU  
          * register method.  This case is unlikely, and supporting it would  
          * be more complicated and might take too much stack.  
          *  
          * Case 4: FPU registers don't belong to anyone: the FPU registers  
          * don't need to be preserved, so we always use the FPU register  
          * method.  CR0_TS must be preserved although it is very likely to  
          * always end up as clear.  
          */  
         cmpl    $0,PCPU(npxthread)  
         je      i586_bz1  
         cmpl    $256+184,%ecx           /* empirical; not quite 2*108 more */  
         jb      intreg_i586_bzero  
         sarb    $1,kernel_fpu_lock  
         jc      intreg_i586_bzero  
         smsw    %ax  
         clts  
         subl    $108,%esp  
         fnsave  0(%esp)  
         jmp     i586_bz2  
   
 i586_bz1:  
         sarb    $1,kernel_fpu_lock  
         jc      intreg_i586_bzero  
         smsw    %ax  
         clts  
         fninit                          /* XXX should avoid needing this */  
 i586_bz2:  
         fldz  
   
         /*  
          * Align to an 8 byte boundary (misalignment in the main loop would  
          * cost a factor of >= 2).  Avoid jumps (at little cost if it is  
          * already aligned) by always zeroing 8 bytes and using the part up  
          * to the _next_ alignment position.  
          */  
         fstl    0(%edx)  
         addl    %edx,%ecx               /* part of %ecx -= new_%edx - %edx */  
         addl    $8,%edx  
         andl    $~7,%edx  
         subl    %edx,%ecx  
   
         /*  
          * Similarly align `len' to a multiple of 8.  
          */  
         fstl    -8(%edx,%ecx)  
         decl    %ecx  
         andl    $~7,%ecx  
   
         /*  
          * This wouldn't be any faster if it were unrolled, since the loop  
          * control instructions are much faster than the fstl and/or done  
          * in parallel with it so their overhead is insignificant.  
          */  
 fpureg_i586_bzero_loop:  
         fstl    0(%edx)  
         addl    $8,%edx  
         subl    $8,%ecx  
         cmpl    $8,%ecx  
         jae     fpureg_i586_bzero_loop  
   
         cmpl    $0,PCPU(npxthread)  
         je      i586_bz3  
         frstor  0(%esp)  
         addl    $108,%esp  
         lmsw    %ax  
         movb    $0xfe,kernel_fpu_lock  
         ret  
   
 i586_bz3:  
         fstp    %st(0)  
         lmsw    %ax  
         movb    $0xfe,kernel_fpu_lock  
         ret  
   
 intreg_i586_bzero:  
         /*  
          * `rep stos' seems to be the best method in practice for small  
          * counts.  Fancy methods usually take too long to start up due  
          * to cache and BTB misses.  
          */  
         pushl   %edi  
         movl    %edx,%edi  
         xorl    %eax,%eax  
         shrl    $2,%ecx  
         cld  
         rep  
         stosl  
         movl    12(%esp),%ecx  
         andl    $3,%ecx  
         jne     1f  
         popl    %edi  
         ret  
   
 1:  
         rep  
         stosb  
         popl    %edi  
         ret  
 #endif /* I586_CPU && NNPX > 0 */  
   
 ENTRY(i686_pagezero)  
         pushl   %edi  
         pushl   %ebx  
   
         movl    12(%esp), %edi  
         movl    $1024, %ecx  
         cld  
   
         ALIGN_TEXT  
 1:  
         xorl    %eax, %eax  
         repe  
         scasl     
         jnz     2f  
   
         popl    %ebx  
         popl    %edi  
         ret  
   
         ALIGN_TEXT  
   
 2:  
         incl    %ecx  
         subl    $4, %edi  
   
         movl    %ecx, %edx  
         cmpl    $16, %ecx  
   
         jge     3f  
   
         movl    %edi, %ebx  
         andl    $0x3f, %ebx  
         shrl    %ebx  
         shrl    %ebx  
         movl    $16, %ecx  
         subl    %ebx, %ecx  
   
 3:  
         subl    %ecx, %edx  
         rep  
         stosl  
   
         movl    %edx, %ecx  
         testl   %edx, %edx  
         jnz     1b  
   
         popl    %ebx  
         popl    %edi  
         ret  
   
 /* fillw(pat, base, cnt) */  /* fillw(pat, base, cnt) */
 ENTRY(fillw)  ENTRY(fillw)
Line 396  ENTRY(fillw) Line 77  ENTRY(fillw)
         popl    %edi          popl    %edi
         ret          ret
   
ENTRY(bcopyb)/*
  * void bcopy(const void *s, void *d, size_t count)
  *
  * Normal bcopy() vector, an optimized bcopy may be installed in
  * bcopy_vector.
  */
 ENTRY(bcopy)
         pushl   %esi          pushl   %esi
         pushl   %edi          pushl   %edi
        movl    12(%esp),%esi        movl    4+8(%esp),%esi                     /* caddr_t from */
        movl    16(%esp),%edi        movl    8+8(%esp),%edi                     /* caddr_t to */
        movl    20(%esp),%ecx        movl    12+8(%esp),%ecx                     /* size_t  len */
        movl    %edi,%eax        call    *bcopy_vector
        subl    %esi,%eax 
        cmpl    %ecx,%eax                        /* overlapping && src < dst? */ 
        jb      1f 
        cld                                     /* nope, copy forwards */ 
        rep 
        movsb 
         popl    %edi          popl    %edi
         popl    %esi          popl    %esi
         ret          ret
   
         ALIGN_TEXT  
 1:  
         addl    %ecx,%edi                       /* copy backwards. */  
         addl    %ecx,%esi  
         decl    %edi  
         decl    %esi  
         std  
         rep  
         movsb  
         popl    %edi  
         popl    %esi  
         cld  
         ret  
   
 ENTRY(bcopy)  
         MEXITCOUNT  
         jmp     *bcopy_vector  
   
 ENTRY(ovbcopy)  
         MEXITCOUNT  
         jmp     *ovbcopy_vector  
   
 /*  /*
 * generic_bcopy(src, dst, cnt) * Generic (integer-only) bcopy() vector.
 *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 
  */   */
 ENTRY(generic_bcopy)  ENTRY(generic_bcopy)
         pushl   %ebp                            /* debugging */  
         movl    %esp,%ebp  
         pushl   %esi          pushl   %esi
         pushl   %edi          pushl   %edi
        movl    16(%esp),%esi        movl    4+8(%esp),%esi                     /* caddr_t from */
        movl    20(%esp),%edi        movl    8+8(%esp),%edi                   /* caddr_t to */
        movl    24(%esp),%ecx        movl    12+8(%esp),%ecx                     /* size_t  len */
        call    asm_generic_bcopy
        movl    %edi,%eax 
        subl    %esi,%eax 
        cmpl    %ecx,%eax                       /* overlapping && src < dst? */ 
        jb      1f 
 
        shrl    $2,%ecx                         /* copy by 32-bit words */ 
        cld                                     /* nope, copy forwards */ 
        rep 
        movsl 
        movl    24(%esp),%ecx 
        andl    $3,%ecx                         /* any bytes left? */ 
        rep 
        movsb 
        popl    %edi 
        popl    %esi 
        popl    %ebp 
        ret 
 
        ALIGN_TEXT 
1: 
        addl    %ecx,%edi                   /* copy backwards */ 
        addl    %ecx,%esi 
        decl    %edi 
        decl    %esi 
        andl    $3,%ecx                         /* any fractional bytes? */ 
        std 
        rep 
        movsb 
        movl    24(%esp),%ecx                     /* copy remainder by 32-bit words */ 
        shrl    $2,%ecx 
        subl    $3,%esi 
        subl    $3,%edi 
        rep 
        movsl 
         popl    %edi          popl    %edi
         popl    %esi          popl    %esi
         popl    %ebp  
         cld  
         ret          ret
   
#if defined(I586_CPU) && NNPX > 0ENTRY(ovbcopy)
ENTRY(i586_bcopy) 
         pushl   %esi          pushl   %esi
         pushl   %edi          pushl   %edi
        movl    12(%esp),%esi        movl    4+8(%esp),%esi                     /* caddr_t from */
        movl    16(%esp),%edi        movl    8+8(%esp),%edi                     /* caddr_t to */
        movl    20(%esp),%ecx        movl    12+8(%esp),%ecx                     /* size_t  len */
        call    *ovbcopy_vector
        movl    %edi,%eax 
        subl    %esi,%eax 
        cmpl    %ecx,%eax                        /* overlapping && src < dst? */ 
        jb      1f 
 
        cmpl    $1024,%ecx 
        jb      small_i586_bcopy 
 
        sarb    $1,kernel_fpu_lock 
        jc      small_i586_bcopy 
        cmpl    $0,PCPU(npxthread) 
        je      i586_bc1 
        smsw    %dx 
        clts 
        subl    $108,%esp 
        fnsave  0(%esp) 
        jmp     4f 
 
i586_bc1: 
        smsw    %dx 
        clts 
        fninit                          /* XXX should avoid needing this */ 
 
        ALIGN_TEXT 
4: 
        pushl   %ecx 
#define DCACHE_SIZE     8192 
        cmpl    $(DCACHE_SIZE-512)/2,%ecx 
        jbe     2f 
        movl    $(DCACHE_SIZE-512)/2,%ecx 
2: 
        subl    %ecx,0(%esp) 
        cmpl    $256,%ecx 
        jb      5f                      /* XXX should prefetch if %ecx >= 32 */ 
        pushl   %esi 
        pushl   %ecx 
        ALIGN_TEXT 
3: 
        movl    0(%esi),%eax 
        movl    32(%esi),%eax 
        movl    64(%esi),%eax 
        movl    96(%esi),%eax 
        movl    128(%esi),%eax 
        movl    160(%esi),%eax 
        movl    192(%esi),%eax 
        movl    224(%esi),%eax 
        addl    $256,%esi 
        subl    $256,%ecx 
        cmpl    $256,%ecx 
        jae     3b 
        popl    %ecx 
        popl    %esi 
5: 
        ALIGN_TEXT 
large_i586_bcopy_loop: 
        fildq   0(%esi) 
        fildq   8(%esi) 
        fildq   16(%esi) 
        fildq   24(%esi) 
        fildq   32(%esi) 
        fildq   40(%esi) 
        fildq   48(%esi) 
        fildq   56(%esi) 
        fistpq  56(%edi) 
        fistpq  48(%edi) 
        fistpq  40(%edi) 
        fistpq  32(%edi) 
        fistpq  24(%edi) 
        fistpq  16(%edi) 
        fistpq  8(%edi) 
        fistpq  0(%edi) 
        addl    $64,%esi 
        addl    $64,%edi 
        subl    $64,%ecx 
        cmpl    $64,%ecx 
        jae     large_i586_bcopy_loop 
        popl    %eax 
        addl    %eax,%ecx 
        cmpl    $64,%ecx 
        jae     4b 
 
        cmpl    $0,PCPU(npxthread) 
        je      i586_bc2 
        frstor  0(%esp) 
        addl    $108,%esp 
i586_bc2: 
        lmsw    %dx 
        movb    $0xfe,kernel_fpu_lock 
 
/* 
 * This is a duplicate of the main part of generic_bcopy.  See the comments 
 * there.  Jumping into generic_bcopy would cost a whole 0-1 cycles and 
 * would mess up high resolution profiling. 
 */ 
        ALIGN_TEXT 
small_i586_bcopy: 
        shrl    $2,%ecx 
        cld 
        rep 
        movsl 
        movl    20(%esp),%ecx 
        andl    $3,%ecx 
        rep 
        movsb 
         popl    %edi          popl    %edi
         popl    %esi          popl    %esi
         ret          ret
   
         ALIGN_TEXT  
 1:  
         addl    %ecx,%edi  
         addl    %ecx,%esi  
         decl    %edi  
         decl    %esi  
         andl    $3,%ecx  
         std  
         rep  
         movsb  
         movl    20(%esp),%ecx  
         shrl    $2,%ecx  
         subl    $3,%esi  
         subl    $3,%edi  
         rep  
         movsl  
         popl    %edi  
         popl    %esi  
         cld  
         ret  
 #endif /* I586_CPU && NNPX > 0 */  
   
 /*  /*
 * Note: memcpy does not support overlapping copies * void *memcpy(void *d, const void *s, size_t count)
  *
  * Note: memcpy does not have to support overlapping copies.
  *
  * Note: (d, s) arguments reversed from bcopy, and memcpy() returns d
  * while bcopy() returns void.
  */   */
 ENTRY(memcpy)  ENTRY(memcpy)
         pushl   %edi  
         pushl   %esi          pushl   %esi
        movl    12(%esp),%edi        pushl   %edi
        movl    16(%esp),%esi        movl    4+8(%esp),%edi
        movl    20(%esp),%ecx        movl    8+8(%esp),%esi
        movl    %edi,%eax        movl    12+8(%esp),%ecx
        shrl    $2,%ecx                         /* copy by 32-bit words */        call    *memcpy_vector
        cld                                     /* nope, copy forwards */        movl    4+8(%esp),%eax
        rep 
        movsl 
        movl    20(%esp),%ecx 
        andl    $3,%ecx                         /* any bytes left? */ 
        rep 
        movsb 
        popl    %esi 
         popl    %edi          popl    %edi
           popl    %esi
         ret          ret
   
   /*
    * A stack-based on-fault routine is used for more complex PCB_ONFAULT
    * situations (such as memcpy/bcopy/bzero).  In this case the on-fault
    * routine must be pushed on the stack.
    */
   stack_onfault:
           ret
   
 /*****************************************************************************/  /*****************************************************************************/
 /* copyout and fubyte family                                                 */  /* copyout and fubyte family                                                 */
Line 671  ENTRY(memcpy) Line 169  ENTRY(memcpy)
  * copyout(from_kernel, to_user, len)  - MP SAFE (if not I386_CPU)   * copyout(from_kernel, to_user, len)  - MP SAFE (if not I386_CPU)
  */   */
 ENTRY(copyout)  ENTRY(copyout)
         MEXITCOUNT  
         jmp     *copyout_vector  
   
 ENTRY(generic_copyout)  
         movl    PCPU(curthread),%eax          movl    PCPU(curthread),%eax
         movl    TD_PCB(%eax),%eax          movl    TD_PCB(%eax),%eax
         movl    $copyout_fault,PCB_ONFAULT(%eax)  
         pushl   %esi          pushl   %esi
         pushl   %edi          pushl   %edi
         pushl   %ebx          pushl   %ebx
        movl    16(%esp),%esi        pushl   $copyout_fault
        movl    20(%esp),%edi        movl    $stack_onfault,PCB_ONFAULT(%eax)
        movl    24(%esp),%ebx        movl    4+16(%esp),%esi
         movl    8+16(%esp),%edi
         movl    12+16(%esp),%ebx
         testl   %ebx,%ebx                       /* anything to do? */          testl   %ebx,%ebx                       /* anything to do? */
         jz      done_copyout          jz      done_copyout
   
Line 765  ENTRY(generic_copyout) Line 260  ENTRY(generic_copyout)
         jnz     1b                              /* check next page */          jnz     1b                              /* check next page */
 #endif /* I386_CPU */  #endif /* I386_CPU */
   
        /* bcopy(%esi, %edi, %ebx) */        /*
          * Convert copyout to memcpy_vector(dest:%edi, src:%esi, conut:%ecx)
          */
 3:  3:
         movl    %ebx,%ecx          movl    %ebx,%ecx
        call    *memcpy_vector
#if defined(I586_CPU) && NNPX > 0 
        ALIGN_TEXT 
slow_copyout: 
#endif 
        shrl    $2,%ecx 
        cld 
        rep 
        movsl 
        movb    %bl,%cl 
        andb    $3,%cl 
        rep 
        movsb 
   
 done_copyout:  done_copyout:
           /*
            * non-error return
            */
           addl    $4,%esp
           movl    PCPU(curthread),%edx
           xorl    %eax,%eax
           movl    TD_PCB(%edx),%edx
         popl    %ebx          popl    %ebx
         popl    %edi          popl    %edi
         popl    %esi          popl    %esi
         xorl    %eax,%eax  
         movl    PCPU(curthread),%edx  
         movl    TD_PCB(%edx),%edx  
         movl    %eax,PCB_ONFAULT(%edx)          movl    %eax,PCB_ONFAULT(%edx)
         ret          ret
   
Line 803  copyout_fault: Line 292  copyout_fault:
         movl    $EFAULT,%eax          movl    $EFAULT,%eax
         ret          ret
   
 #if defined(I586_CPU) && NNPX > 0  
 ENTRY(i586_copyout)  
         /*  
          * Duplicated from generic_copyout.  Could be done a bit better.  
          */  
         movl    PCPU(curthread),%eax  
         movl    TD_PCB(%eax),%eax  
         movl    $copyout_fault,PCB_ONFAULT(%eax)  
         pushl   %esi  
         pushl   %edi  
         pushl   %ebx  
         movl    16(%esp),%esi  
         movl    20(%esp),%edi  
         movl    24(%esp),%ebx  
         testl   %ebx,%ebx                       /* anything to do? */  
         jz      done_copyout  
   
         /*  
          * Check explicitly for non-user addresses.  If 486 write protection  
          * is being used, this check is essential because we are in kernel  
          * mode so the h/w does not provide any protection against writing  
          * kernel addresses.  
          */  
   
         /*  
          * First, prevent address wrapping.  
          */  
         movl    %edi,%eax  
         addl    %ebx,%eax  
         jc      copyout_fault  
 /*  
  * XXX STOP USING VM_MAXUSER_ADDRESS.  
  * It is an end address, not a max, so every time it is used correctly it  
  * looks like there is an off by one error, and of course it caused an off  
  * by one error in several places.  
  */  
         cmpl    $VM_MAXUSER_ADDRESS,%eax  
         ja      copyout_fault  
   
         /* bcopy(%esi, %edi, %ebx) */  
 3:  
         movl    %ebx,%ecx  
         /*  
          * End of duplicated code.  
          */  
   
         cmpl    $1024,%ecx  
         jb      slow_copyout  
   
         pushl   %ecx  
         call    fastmove  
         addl    $4,%esp  
         jmp     done_copyout  
 #endif /* I586_CPU && NNPX > 0 */  
   
 /*  /*
  * copyin(from_user, to_kernel, len) - MP SAFE   * copyin(from_user, to_kernel, len) - MP SAFE
  */   */
 ENTRY(copyin)  
         MEXITCOUNT  
         jmp     *copyin_vector  
   
ENTRY(generic_copyin)ENTRY(copyin)
         movl    PCPU(curthread),%eax          movl    PCPU(curthread),%eax
         movl    TD_PCB(%eax),%eax          movl    TD_PCB(%eax),%eax
         movl    $copyin_fault,PCB_ONFAULT(%eax)  
         pushl   %esi          pushl   %esi
         pushl   %edi          pushl   %edi
        movl    12(%esp),%esi                   /* caddr_t from */        pushl   $copyin_fault
        movl    16(%esp),%edi                     /* caddr_t to */        movl    $stack_onfault,PCB_ONFAULT(%eax)
        movl    20(%esp),%ecx                     /* size_t  len */        movl    4+12(%esp),%esi                   /* caddr_t from */
         movl    8+12(%esp),%edi                     /* caddr_t to */
         movl    12+12(%esp),%ecx             /* size_t  len */
   
         /*          /*
          * make sure address is valid           * make sure address is valid
Line 884  ENTRY(generic_copyin) Line 316  ENTRY(generic_copyin)
         cmpl    $VM_MAXUSER_ADDRESS,%edx          cmpl    $VM_MAXUSER_ADDRESS,%edx
         ja      copyin_fault          ja      copyin_fault
   
#if defined(I586_CPU) && NNPX > 0        /*
        ALIGN_TEXT         * Call memcpy(destination:%edi, source:%esi, bytes:%ecx)
slow_copyin:         */
#endif        call    *memcpy_vector
        movb    %cl,%al 
        shrl    $2,%ecx                         /* copy longword-wise */ 
        cld 
        rep 
        movsl 
        movb    %al,%cl 
        andb    $3,%cl                          /* copy remaining bytes */ 
        rep 
        movsb 
   
#if defined(I586_CPU) && NNPX > 0        /*
        ALIGN_TEXT         * return 0 (no error)
done_copyin:         */
#endif        addl    $4,%esp
        popl    %edi 
        popl    %esi 
        xorl    %eax,%eax 
         movl    PCPU(curthread),%edx          movl    PCPU(curthread),%edx
           xorl    %eax,%eax
         movl    TD_PCB(%edx),%edx          movl    TD_PCB(%edx),%edx
         movl    %eax,PCB_ONFAULT(%edx)  
         ret  
   
         ALIGN_TEXT  
 copyin_fault:  
         popl    %edi          popl    %edi
         popl    %esi          popl    %esi
        movl    PCPU(curthread),%edx        movl    %eax,PCB_ONFAULT(%edx)
        movl    TD_PCB(%edx),%edx 
        movl    $0,PCB_ONFAULT(%edx) 
        movl    $EFAULT,%eax 
         ret          ret
   
 #if defined(I586_CPU) && NNPX > 0  
 ENTRY(i586_copyin)  
         /*  
          * Duplicated from generic_copyin.  Could be done a bit better.  
          */  
         movl    PCPU(curthread),%eax  
         movl    TD_PCB(%eax),%eax  
         movl    $copyin_fault,PCB_ONFAULT(%eax)  
         pushl   %esi  
         pushl   %edi  
         movl    12(%esp),%esi                   /* caddr_t from */  
         movl    16(%esp),%edi                   /* caddr_t to */  
         movl    20(%esp),%ecx                   /* size_t  len */  
   
         /*          /*
         * make sure address is valid         * return EFAULT
          */           */
         movl    %esi,%edx  
         addl    %ecx,%edx  
         jc      copyin_fault  
         cmpl    $VM_MAXUSER_ADDRESS,%edx  
         ja      copyin_fault  
         /*  
          * End of duplicated code.  
          */  
   
         cmpl    $1024,%ecx  
         jb      slow_copyin  
   
         pushl   %ebx                    /* XXX prepare for fastmove_fault */  
         pushl   %ecx  
         call    fastmove  
         addl    $8,%esp  
         jmp     done_copyin  
 #endif /* I586_CPU && NNPX > 0 */  
   
 #if defined(I586_CPU) && NNPX > 0  
 /* fastmove(src, dst, len)  
         src in %esi  
         dst in %edi  
         len in %ecx             XXX changed to on stack for profiling  
         uses %eax and %edx for tmp. storage  
  */  
 /* XXX use ENTRY() to get profiling.  fastmove() is actually a non-entry. */  
 ENTRY(fastmove)  
         pushl   %ebp  
         movl    %esp,%ebp  
         subl    $PCB_SAVE87_SIZE+3*4,%esp  
   
         movl    8(%ebp),%ecx  
         cmpl    $63,%ecx  
         jbe     fastmove_tail  
   
         testl   $7,%esi /* check if src addr is multiple of 8 */  
         jnz     fastmove_tail  
   
         testl   $7,%edi /* check if dst addr is multiple of 8 */  
         jnz     fastmove_tail  
   
 /* if (npxthread != NULL) { */  
         cmpl    $0,PCPU(npxthread)  
         je      6f  
 /*    fnsave(&curpcb->pcb_savefpu); */  
         movl    PCPU(curthread),%eax  
         movl    TD_PCB(%eax),%eax  
         fnsave  PCB_SAVEFPU(%eax)  
 /*   npxthread = NULL; */  
         movl    $0,PCPU(npxthread)  
 /* } */  
 6:  
 /* now we own the FPU. */  
   
 /*  
  * The process' FP state is saved in the pcb, but if we get  
  * switched, the cpu_switch() will store our FP state in the  
  * pcb.  It should be possible to avoid all the copying for  
  * this, e.g., by setting a flag to tell cpu_switch() to  
  * save the state somewhere else.  
  */  
 /* tmp = curpcb->pcb_savefpu; */  
         movl    %ecx,-12(%ebp)  
         movl    %esi,-8(%ebp)  
         movl    %edi,-4(%ebp)  
         movl    %esp,%edi  
         movl    PCPU(curthread),%esi  
         movl    TD_PCB(%esi),%esi  
         addl    $PCB_SAVEFPU,%esi  
         cld  
         movl    $PCB_SAVE87_SIZE>>2,%ecx  
         rep  
         movsl  
         movl    -12(%ebp),%ecx  
         movl    -8(%ebp),%esi  
         movl    -4(%ebp),%edi  
 /* stop_emulating(); */  
         clts  
 /* npxthread = curthread; */  
         movl    PCPU(curthread),%eax  
         movl    %eax,PCPU(npxthread)  
         movl    PCPU(curthread),%eax  
         movl    TD_PCB(%eax),%eax  
         movl    $fastmove_fault,PCB_ONFAULT(%eax)  
 4:  
         movl    %ecx,-12(%ebp)  
         cmpl    $1792,%ecx  
         jbe     2f  
         movl    $1792,%ecx  
 2:  
         subl    %ecx,-12(%ebp)  
         cmpl    $256,%ecx  
         jb      5f  
         movl    %ecx,-8(%ebp)  
         movl    %esi,-4(%ebp)  
         ALIGN_TEXT  
 3:  
         movl    0(%esi),%eax  
         movl    32(%esi),%eax  
         movl    64(%esi),%eax  
         movl    96(%esi),%eax  
         movl    128(%esi),%eax  
         movl    160(%esi),%eax  
         movl    192(%esi),%eax  
         movl    224(%esi),%eax  
         addl    $256,%esi  
         subl    $256,%ecx  
         cmpl    $256,%ecx  
         jae     3b  
         movl    -8(%ebp),%ecx  
         movl    -4(%ebp),%esi  
 5:  
         ALIGN_TEXT  
 fastmove_loop:  
         fildq   0(%esi)  
         fildq   8(%esi)  
         fildq   16(%esi)  
         fildq   24(%esi)  
         fildq   32(%esi)  
         fildq   40(%esi)  
         fildq   48(%esi)  
         fildq   56(%esi)  
         fistpq  56(%edi)  
         fistpq  48(%edi)  
         fistpq  40(%edi)  
         fistpq  32(%edi)  
         fistpq  24(%edi)  
         fistpq  16(%edi)  
         fistpq  8(%edi)  
         fistpq  0(%edi)  
         addl    $-64,%ecx  
         addl    $64,%esi  
         addl    $64,%edi  
         cmpl    $63,%ecx  
         ja      fastmove_loop  
         movl    -12(%ebp),%eax  
         addl    %eax,%ecx  
         cmpl    $64,%ecx  
         jae     4b  
   
 /* curpcb->pcb_savefpu = tmp; */  
         movl    %ecx,-12(%ebp)  
         movl    %esi,-8(%ebp)  
         movl    %edi,-4(%ebp)  
         movl    PCPU(curthread),%edi  
         movl    TD_PCB(%edi),%edi  
         addl    $PCB_SAVEFPU,%edi  
         movl    %esp,%esi  
         cld  
         movl    $PCB_SAVE87_SIZE>>2,%ecx  
         rep  
         movsl  
         movl    -12(%ebp),%ecx  
         movl    -8(%ebp),%esi  
         movl    -4(%ebp),%edi  
   
 /* start_emulating(); */  
         smsw    %ax  
         orb     $CR0_TS,%al  
         lmsw    %ax  
 /* npxthread = NULL; */  
         movl    $0,PCPU(npxthread)  
   
         ALIGN_TEXT  
 fastmove_tail:  
         movl    PCPU(curthread),%eax  
         movl    TD_PCB(%eax),%eax  
         movl    $fastmove_tail_fault,PCB_ONFAULT(%eax)  
   
         movb    %cl,%al  
         shrl    $2,%ecx                         /* copy longword-wise */  
         cld  
         rep  
         movsl  
         movb    %al,%cl  
         andb    $3,%cl                          /* copy remaining bytes */  
         rep  
         movsb  
   
         movl    %ebp,%esp  
         popl    %ebp  
         ret  
   
         ALIGN_TEXT          ALIGN_TEXT
fastmove_fault:copyin_fault:
        movl    PCPU(curthread),%edi 
        movl    TD_PCB(%edi),%edi 
        addl    $PCB_SAVEFPU,%edi 
        movl    %esp,%esi 
        cld 
        movl    $PCB_SAVE87_SIZE>>2,%ecx 
        rep 
        movsl 
 
        smsw    %ax 
        orb     $CR0_TS,%al 
        lmsw    %ax 
        movl    $0,PCPU(npxthread) 
 
fastmove_tail_fault: 
        movl    %ebp,%esp 
        popl    %ebp 
        addl    $8,%esp 
        popl    %ebx 
         popl    %edi          popl    %edi
         popl    %esi          popl    %esi
         movl    PCPU(curthread),%edx          movl    PCPU(curthread),%edx
Line 1149  fastmove_tail_fault: Line 345  fastmove_tail_fault:
         movl    $0,PCB_ONFAULT(%edx)          movl    $0,PCB_ONFAULT(%edx)
         movl    $EFAULT,%eax          movl    $EFAULT,%eax
         ret          ret
 #endif /* I586_CPU && NNPX > 0 */  
   
 /*  /*
  * fu{byte,sword,word} - MP SAFE   * fu{byte,sword,word} - MP SAFE

Removed from v.1.10  
changed lines
  Added in v.1.11