/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/asm_linkage.h>
#include <sys/machthread.h>
#include <sys/privregs.h>
#if !defined(lint)
#include "assym.h"
#endif /* lint */
/*
* Pseudo-code to aid in understanding the control flow of the
* bcopy routine.
*
* On entry to bcopy:
*
* %l6 = curthread->t_lofault;
* used_block_copy = FALSE; ! %l6 |= 1
* if (%l6 != NULL) {
* curthread->t_lofault = .copyerr;
* caller_error_handler = TRUE ! %l6 |= 2
* }
*
* if (length < VIS_COPY)
* goto regular_copy;
*
* if (!use_vis)
* goto_regular_copy;
*
* if (curthread->t_lwp == NULL) {
* ! Kernel threads do not have pcb's in which to store
* ! the floating point state, disallow preemption during
* ! the copy.
* kpreempt_disable(curthread);
* }
*
* old_fprs = %fprs;
* old_gsr = %gsr;
* if (%fprs.fef) {
* ! If we need to save 4 blocks of fpregs then make sure
* ! the length is still appropriate for that extra overhead.
* if (length < (large_length + (64 * 4))) {
* if (curthread->t_lwp == NULL)
* kpreempt_enable(curthread);
* goto regular_copy;
* }
* %fprs.fef = 1;
* save current fpregs on stack using blockstore
* } else {
* %fprs.fef = 1;
* }
*
* used_block_copy = 1; ! %l6 |= 1
* do_blockcopy_here;
*
* In lofault handler:
* curthread->t_lofault = .copyerr2;
* Continue on with the normal exit handler
*
* On exit:
* call_kpreempt = 0;
* if (used_block_copy) { ! %l6 & 1
* %gsr = old_gsr;
* if (old_fprs & FPRS_FEF)
* restore fpregs from stack using blockload
* else
* zero fpregs
* %fprs = old_fprs;
* if (curthread->t_lwp == NULL) {
* kpreempt_enable(curthread);
* call_kpreempt = 1;
* }
* }
* curthread->t_lofault = (%l6 & ~3);
* if (call_kpreempt)
* kpreempt(%pil);
* return (0)
*
* In second lofault handler (.copyerr2):
* We've tried to restore fp state from the stack and failed. To
* prevent from returning with a corrupted fp state, we will panic.
*/
/*
* Notes on preserving existing fp state:
*
* When a copyOP decides to use fp we may have to preserve existing
* floating point state. It is not the caller's state that we need to
* preserve - the rest of the kernel does not use fp and, anyway, fp
* registers are volatile across a call. Some examples:
*
* - userland has fp state and is interrupted (device interrupt
* bcopy()
* - another (higher level) interrupt or trap handler uses bcopy
* while a bcopy from an earlier interrupt is still active
* - an asynchronous error trap occurs while fp state exists (in
* userland or in kernel copy) and the tl0 component of the handling
* uses bcopy
* - a user process with fp state incurs a copy-on-write fault and
* hwblkpagecopy always uses fp
*
* We therefore need a per-call place in which to preserve fp state -
* using our stack is ideal (and since fp copy cannot be leaf optimized
* because of calls it makes, this is no hardship).
*
* To make sure that floating point state is always saved and restored
* correctly, the following "big rules" must be followed when the floating
* point registers will be used:
*
* 1. %l6 always holds the caller's lofault handler. Also in this register,
* Bit 1 (FPUSED_FLAG) indicates that the floating point registers are in
* use. Bit 2 (BCOPY_FLAG) indicates that the call was to bcopy.
*
* 2. The FPUSED flag indicates that all FP state has been successfully stored
* on the stack. It should not be set until this save has been completed.
*
* 3. The FPUSED flag should not be cleared on exit until all FP state has
* been restored from the stack. If an error occurs while restoring
* data from the stack, the error handler can check this flag to see if
* a restore is necessary.
*
* 4. Code run under the new lofault handler must be kept to a minimum. In
* particular, any calls to kpreempt() should not be made until after the
* lofault handler has been restored.
*/
/*
* This shadows sys/machsystm.h which can't be included due to the lack of
* _ASM guards in include files it references. Change it here, change it there.
*/
/*
* Less then or equal this number of bytes we will always copy byte-for-byte
*/
/*
* Flags set in the lower bits of the t_lofault address:
* FPUSED_FLAG: The FP registers were in use and must be restored
* BCOPY_FLAG: Set for bcopy calls, cleared for kcopy calls
* COPY_FLAGS: Both of the above
*
* Other flags:
* KPREEMPT_FLAG: kpreempt needs to be called
*/
/*
* Size of stack frame in order to accomodate a 64-byte aligned
* floating-point register save area and 2 32-bit temp locations.
*/
/*
* Common macros used by the various versions of the block copy
* routines in this file.
*/
#define FZERO \
#define FALIGN_D0 \
#define FALIGN_D16 \
#define FALIGN_D32 \
#define FALIGN_D2 \
#define FALIGN_D18 \
#define FALIGN_D34 \
#define FALIGN_D4 \
#define FALIGN_D20 \
#define FALIGN_D36 \
#define FALIGN_D6 \
#define FALIGN_D22 \
#define FALIGN_D38 \
#define FALIGN_D8 \
#define FALIGN_D24 \
#define FALIGN_D40 \
#define FALIGN_D10 \
#define FALIGN_D26 \
#define FALIGN_D42 \
#define FALIGN_D12 \
#define FALIGN_D28 \
#define FALIGN_D44 \
#define FALIGN_D14 \
#define FALIGN_D30 \
#define FALIGN_D46 \
/*
* Copy a block of storage, returning an error code if `from' or
* `to' takes a kernel pagefault which cannot be resolved.
* Returns errno value on pagefault error, 0 if all ok
*/
#if defined(lint)
/* ARGSUSED */
int
{ return(0); }
#else /* lint */
.seg ".text"
.align 4
!
! t_lofault.
!
/*
* We got here because of a fault during kcopy or bcopy if a fault
* handler existed when bcopy was called.
* Errno value is in %g1.
*/
.copyerr:
4:
!
! and *not* to invoke any existing error handler. As far as
! bcopy is concerned, we only set t_lofault if there was an
!
1:
2:
3:
!
! We're here via bcopy. There *must* have been an error handler
! in place otheerwise we would have died a nasty death already.
!
jmp %l6 ! goto real handler
restore %g0, 0, %o0 ! dispose of copy window
/*
*/
.asciz "Unable to restore fp state after copy operation"
.align 4
.copyerr2:
#endif /* lint */
/*
* Copy a block of storage - must not overlap (from + len <= to).
* Registers: l6 - saved t_lofault
*
* Copy a page of memory.
* Assumes double word alignment and a count >= 256.
*/
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
!
! We've already captured whether t_lofault was zero on entry.
! We need to mark ourselves as being from bcopy since both
! kcopy and bcopy use the same code path. If BCOPY_FLAG is set
! returning.
!
.do_copy:
!
!
1:
/*
* Compare against 256 since we should be checking block addresses
* and (dest & ~63) - (src & ~63) can be 3 blocks even if
* src = dest + (64 * 3) + 63.
*/
! kpreempt_disable();
1:
1:
! out
6:
sqtr:
hlf:
fqtr:
seg0:
0:
1:
2:
seg1:
0:
1:
2:
seg2:
0:
1:
2:
seg3:
0:
1:
2:
seg4:
0:
1:
2:
seg5:
0:
1:
2:
seg6:
0:
1:
2:
seg7:
0:
1:
2:
!
!
1:
.bcb_exit:
4:
1:
!
!
!
! then return.
!
2:
!
!
3:
4:
.bcb_punt:
!
!
!
!
!
!
bnz,a 1b
1:
bnz,a 1b
b 2f
b 3f
!
!
1:
bnz,a 1b
.xfer:
3:
2:
b 2b ! loop
1:
!
!
b,a .xfer
!
!
.aldoubcp:
!
!
5:
!
!
.wordcp:
5:
b,a .dbytecp
.alwordcp:
b .wordcp
!
!
.bytecp:
b .dbytecp
!
!
1:
.dbytecp:
!
!
.cpdone:
!
!
!
!
!
!
2:
/*
* Common code used to align transfers on word and doubleword
* boudaries. Aligns source and destination and returns a count
* of aligned bytes to transfer in %i3
*/
1:
.alignit:
bnz,a 1b
#endif /* lint */
/*
* Block copy with possibly overlapped operands.
*/
#if defined(lint)
/*ARGSUSED*/
void
{}
#else /* lint */
retl ! return
1:
!
!
.ov_fwd:
retl ! return
!
!
.ov_bkwd:
retl ! return
#endif /* lint */
/*
* hwblkpagecopy()
*
* Copies exactly one page. This routine assumes the caller (ppcopy)
* has already disabled kernel preemption and has checked
* use_hw_bcopy.
*/
#ifdef lint
/*ARGSUSED*/
void
{ }
#else /* lint */
bz 1f
bz 4f
#endif /* lint */
/*
* Transfer data to and from user space -
* Note that these routines can cause faults
* It is assumed that the kernel has nothing at
* less than KERNELBASE in the virtual address space.
*
* Note that copyin(9F) and copyout(9F) are part of the
*
* Sigh.
*
* So there's two extremely similar routines - xcopyin() and xcopyout()
* which return the errno that we've faithfully computed. This
* allows other callers (e.g. uiomove(9F)) to work correctly.
* Given that these are used pretty heavily, we expand the calling
* sequences inline for all flavours (rather than making wrappers).
*
* There are also stub routines for xcopyout_little and xcopyin_little,
* which currently are intended to handle requests of <= 16 bytes from
* do_unaligned. Future enhancement to make them handle 8k pages efficiently
* is left as an exercise...
*/
/*
* Copy user data to kernel space (copyOP/xcopyOP/copyOP_noerr)
*
* General theory of operation:
*
* The only difference between default_copy{in,out} and
* default_xcopy{in,out} is in the error handling routine they invoke
* when a memory access error is seen. default_xcopyOP returns the errno
* while default_copyOP returns -1 (see above). copy{in,out}_noerr set
* a special flag (by oring the value 2 into the fault handler address)
* if they are called with a fault handler already in place. That flag
* causes the default handlers to trampoline to the previous handler
* upon an error.
*
* None of the copyops routines grab a window until it's decided that
* we need to do a HW block copy operation. This saves a window
*
* This code uses a set of 4 limits for the maximum size that will
* the default limits are:
*
* single byte aligned - 900 (hw_copy_limit_1)
* two byte aligned - 1800 (hw_copy_limit_2)
* four byte aligned - 3600 (hw_copy_limit_4)
* eight byte aligned - 7200 (hw_copy_limit_8)
*
* If the value for a particular limit is zero, the copy will be done
* via the copy loops rather than VIS.
*
* Flow:
*
* If count == zero return zero.
*
* Store the previous lo_fault handler into %g6.
* Place our secondary lofault handler into %g5.
* Place the address of our nowindow fault handler into %o3.
* Place the address of the windowed fault handler into %o4.
* --> We'll use this handler if we end up grabbing a window
* --> before we use VIS instructions.
*
* If count is less than or equal to SMALL_LIMIT (7) we
* always do a byte for byte copy.
*
* If count is > SMALL_LIMIT, we check the alignment of the input
* and output pointers. Based on the alignment we check count
* against a soft limit of VIS_COPY_THRESHOLD (900 on spitfire). If
* we're larger than VIS_COPY_THRESHOLD, we check against a limit based
* on detected alignment. If we exceed the alignment value we copy
* via VIS instructions.
*
* If we don't exceed one of the limits, we store -count in %o3,
* we store the number of chunks (8, 4, 2 or 1 byte) operated
* on in our basic copy loop in %o2. Following this we branch
* to the appropriate copy loop and copy that many chunks.
* Since we've been adding the chunk size to %o3 each time through
* as well as decrementing %o2, we can tell if any data is
* is left to be copied by examining %o3. If that is zero, we're
* done and can go home. If not, we figure out what the largest
* chunk size left to be copied is and branch to that copy loop
* unless there's only one byte left. We load that as we're
* branching to code that stores it just before we return.
*
* There is one potential situation in which we start to do a VIS
* copy but decide to punt and return to the copy loops. There is
* (in the default configuration) a window of 256 bytes between
* the single byte aligned copy limit and what VIS treats as its
* minimum if floating point is in use in the calling app. We need
* to be prepared to handle this. See the .small_copyOP label for
* details.
*
* Fault handlers are invoked if we reference memory that has no
* current mapping. All forms share the same copyio_fault handler.
* This routine handles fixing up the stack and general housecleaning.
* Each copy operation has a simple fault handler that is then called
* to do the work specific to the invidual operation. The handlers
* for default_copyOP and copyOP_noerr are found at the end of
* default_copyout. The handlers for default_xcopyOP are found at the
* end of xdefault_copyin.
*/
/*
* Copy kernel data to user space (copyout/xcopyout/xcopyout_little).
*/
#if defined(lint)
/*ARGSUSED*/
int
{ return (0); }
#else /* lint */
/*
* We save the arguments in the following registers in case of a fault:
* kaddr - %g2
* uaddr - %g3
* count - %g4
*/
/*
* Generic copyio fault handler. This is the first line of defense when a
* fault occurs in (x)copyin/(x)copyout. In order for this to function
* properly, the value of the 'real' lofault handler should be in REAL_LOFAULT.
* This allows us to share common code for all the flavors of the copy
* operations, including the _noerr versions.
*
* Note that this function will restore the original input parameters before
* calling REAL_LOFAULT. So the real handler can vector to the appropriate
* member of the t_copyop structure, if needed.
*/
bz 1f
bz 4f
4:
1:
!
!
1:
!
! Run in leaf mode, using the %o regs as our input regs.
!
subcc %o2, SMALL_LIMIT, %o3
bgu,a,pt %ncc, .dco_ns
or %o0, %o1, %o3
!
! What was previously ".small_copyout"
! Do full differenced copy.
!
.dcobcp:
sub %g0, %o2, %o3 ! negate count
add %o0, %o2, %o0 ! make %o0 point at the end
add %o1, %o2, %o1 ! make %o1 point at the end
ba,pt %ncc, .dcocl
ldub [%o0 + %o3], %o4 ! load first byte
!
! %o0 and %o2 point at the end and remain pointing at the end
! of their buffers. We pull things out by adding %o3 (which is
! the negation of the length) to the buffer end which gives us
! the curent location in the buffers. By incrementing %o3 we walk
! through both buffers without having to bump each buffer's
!
.align 16
.dcocl:
!
! We're done. Go home.
!
membar #Sync
stn SAVED_LOFAULT, [THREAD_REG + T_LOFAULT]
retl
clr %o0
!
! Try aligned copies from here.
!
.dco_ns:
! %o0 = kernel addr (to be copied from)
! %o1 = user addr (to be copied to)
! %o2 = length
! %o3 = %o1 | %o2 (used for alignment checking)
! %o4 is alternate lo_fault
! %o5 is original lo_fault
!
! bounce to the byte for byte copy loop. Otherwise do it in
! HW (if enabled).
!
btst 1, %o3
bz,pt %icc, .dcoh8
btst 7, %o3
!
! Single byte aligned. Do we do it via HW or via
! byte for byte? Do a quick no memory reference
! check to pick up small copies.
!
subcc %o2, VIS_COPY_THRESHOLD, %o3
bleu,pt %ncc, .dcobcp
sethi %hi(hw_copy_limit_1), %o3
!
! Big enough that we need to check the HW limit for
! this size copy.
!
ld [%o3 + %lo(hw_copy_limit_1)], %o3
!
! Is HW copy on? If not, do everything byte for byte.
!
tst %o3
bz,pn %icc, .dcobcp
subcc %o3, %o2, %o3
!
!
!
! We're big enough and copy is on. Do it with HW.
!
ba,pt %ncc, .big_copyout
nop
.dcoh8:
!
! 8 byte aligned?
!
bnz,a %ncc, .dcoh4
btst 3, %o3
!
!
!
!
!
! We're negative if our size is larger than hw_copy_limit_8.
!
bge,pt %ncc, .dcos8
nop
!
!
.dcos8:
!
!
!
!
.dcoh4:
!
! If so, go off an do the copy.
! If not, load the hard limit. %o3 is
! available for reuse.
!
subcc %o2, VIS_COPY_THRESHOLD, %o3
bleu,pt %ncc, .dcos4
sethi %hi(hw_copy_limit_4), %o3
ld [%o3 + %lo(hw_copy_limit_4)], %o3
!
! Bop off to the aligned copy.
!
tst %o3
bz,pn %icc, .dcos4
subcc %o3, %o2, %o3
!
!
!
!
ba,pt %ncc, .big_copyout
nop
.dcos4:
add %o0, %o2, %o0
add %o1, %o2, %o1
sub %g0, %o2, %o3
ba,pt %ncc, .dodfbc
srl %o2, 2, %o2 ! Number of 4 byte chunks to copy
!
! We must be 2 byte aligned. Off we go.
! The check for small copies was done in the
! delay at .dcoh4
!
.dcoh2:
ble %ncc, .dcos2
sethi %hi(hw_copy_limit_2), %o3
ld [%o3 + %lo(hw_copy_limit_2)], %o3
tst %o3
bz,pn %icc, .dcos2
subcc %o3, %o2, %o3
bge,pt %ncc, .dcos2
nop
!
!
.dcos2:
!
!
!
.align 32
.dodebc:
!
! eight byte aligned copies end here.
!
bz,pt %ncc, .dcofh
nop
!
! Something is left - do it byte for byte.
!
ba,pt %ncc, .dcocl
ldub [%o0 + %o3], %o4 ! load next byte
!
! Four byte copy loop. %o2 is the number of 4 byte chunks to copy.
!
.align 32
.dodfbc:
lduw [%o0 + %o3], %o4
deccc %o2
sta %o4, [%o1 + %o3]ASI_USER
bg,pt %ncc, .dodfbc
addcc %o3, 4, %o3
!
!
!
!
!
! copy.
!
.align 32
.dodtbc:
!
!
!
!
.dcofh:
!
!
!
! We're going to go off and do a block copy.
! Switch fault hendlers and grab a window. We
! kernel data to this point.
!
stn %o4, [THREAD_REG + T_LOFAULT]
save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp
!
! %o3 is now %i3. Save original %fprs.
!
st %i3, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET]
ba,pt %ncc, .do_block_copyout ! Not in use. Go off and do it.
wr %g0, FPRS_FEF, %fprs ! clear %fprs
!
.copyout_fpregs_inuse:
!
!
!
! We're going to go off and do a block copy.
! Change to the heavy duty fault handler and grab a window first.
!
stn %o4, [THREAD_REG + T_LOFAULT]
save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp
st %i3, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET]
!
! save in-use fpregs on stack
!
wr %g0, FPRS_FEF, %fprs
membar #Sync
add %fp, STACK_BIAS - 257, %o2
and %o2, -64, %o2
stda %d0, [%o2]ASI_BLK_P
add %o2, 64, %o2
stda %d16, [%o2]ASI_BLK_P
add %o2, 64, %o2
stda %d32, [%o2]ASI_BLK_P
add %o2, 64, %o2
stda %d48, [%o2]ASI_BLK_P
membar #Sync
.do_block_copyout:
membar #StoreStore|#StoreLoad|#LoadStore
rd %gsr, %o2
st %o2, [%fp + STACK_BIAS - SAVED_GSR_OFFSET] ! save gsr
! Set the lower bit in the saved t_lofault to indicate
! that we need to clear the %fprs register on the way
! out
or SAVED_LOFAULT, FPUSED_FLAG, SAVED_LOFAULT
mov %i1, %i5
mov %i0, %i1
mov %i5, %i0
!!! This code is nearly identical to the version in the sun4u
!!! libc_psr. Most bugfixes made to that file should be
!!! merged into this routine.
andcc %i0, 7, %o3
bz %ncc, copyout_blkcpy
sub %o3, 8, %o3
neg %o3
sub %i2, %o3, %i2
! Align Destination on double-word boundary
2: ldub [%i1], %o4
inc %i1
stba %o4, [%i0]ASI_USER
deccc %o3
bgu %ncc, 2b
inc %i0
copyout_blkcpy:
andcc %i0, 63, %i3
bz,pn %ncc, copyout_blalign ! now block aligned
sub %i3, 64, %i3
neg %i3 ! bytes till block aligned
sub %i2, %i3, %i2 ! update %i2 with new count
! Copy %i3 bytes till dst is block (64 byte) aligned. use
! double word copies.
alignaddr %i1, %g0, %g1
ldd [%g1], %d0
add %g1, 8, %g1
6:
ldd [%g1], %d2
add %g1, 8, %g1
subcc %i3, 8, %i3
faligndata %d0, %d2, %d8
stda %d8, [%i0]ASI_USER
add %i1, 8, %i1
bz,pn %ncc, copyout_blalign
add %i0, 8, %i0
ldd [%g1], %d0
add %g1, 8, %g1
subcc %i3, 8, %i3
faligndata %d2, %d0, %d8
stda %d8, [%i0]ASI_USER
add %i1, 8, %i1
bgu,pn %ncc, 6b
add %i0, 8, %i0
copyout_blalign:
membar #StoreLoad
! %i2 = total length
! %i3 = blocks (length - 64) / 64
! %i4 = doubles remaining (length - blocks)
sub %i2, 64, %i3
andn %i3, 63, %i3
sub %i2, %i3, %i4
andn %i4, 7, %i4
sub %i4, 16, %i4
sub %i2, %i4, %i2
sub %i2, %i3, %i2
andn %i1, 0x3f, %l7 ! blk aligned address
alignaddr %i1, %g0, %g0 ! gen %gsr
srl %i1, 3, %l5 ! bits 3,4,5 are now least sig in %l5
andcc %l5, 7, %i5 ! mask everything except bits 1,2 3
add %i1, %i4, %i1
add %i1, %i3, %i1
ldda [%l7]ASI_BLK_P, %d0
add %l7, 64, %l7
ldda [%l7]ASI_BLK_P, %d16
add %l7, 64, %l7
ldda [%l7]ASI_BLK_P, %d32
add %l7, 64, %l7
sub %i3, 128, %i3
! switch statement to get us to the right 8 byte blk within a
! 64 byte block
cmp %i5, 4
bgeu,a copyout_hlf
cmp %i5, 6
cmp %i5, 2
bgeu,a copyout_sqtr
nop
cmp %i5, 1
be,a copyout_seg1
nop
ba,pt %ncc, copyout_seg0
nop
copyout_sqtr:
be,a copyout_seg2
nop
ba,pt %ncc, copyout_seg3
nop
copyout_hlf:
bgeu,a copyout_fqtr
nop
cmp %i5, 5
be,a copyout_seg5
nop
ba,pt %ncc, copyout_seg4
nop
copyout_fqtr:
be,a copyout_seg6
nop
ba,pt %ncc, copyout_seg7
nop
copyout_seg0:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D0
ldda [%l7]ASI_BLK_P, %d0
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D16
ldda [%l7]ASI_BLK_P, %d16
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D32
ldda [%l7]ASI_BLK_P, %d32
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyout_seg0
0:
FALIGN_D16
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D32
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd0
add %i0, 64, %i0
1:
FALIGN_D32
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D0
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd16
add %i0, 64, %i0
2:
FALIGN_D0
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D16
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd32
add %i0, 64, %i0
copyout_seg1:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D2
ldda [%l7]ASI_BLK_P, %d0
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D18
ldda [%l7]ASI_BLK_P, %d16
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D34
ldda [%l7]ASI_BLK_P, %d32
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyout_seg1
0:
FALIGN_D18
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D34
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd2
add %i0, 64, %i0
1:
FALIGN_D34
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D2
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd18
add %i0, 64, %i0
2:
FALIGN_D2
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D18
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd34
add %i0, 64, %i0
copyout_seg2:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D4
ldda [%l7]ASI_BLK_P, %d0
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D20
ldda [%l7]ASI_BLK_P, %d16
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D36
ldda [%l7]ASI_BLK_P, %d32
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyout_seg2
0:
FALIGN_D20
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D36
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd4
add %i0, 64, %i0
1:
FALIGN_D36
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D4
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd20
add %i0, 64, %i0
2:
FALIGN_D4
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D20
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd36
add %i0, 64, %i0
copyout_seg3:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D6
ldda [%l7]ASI_BLK_P, %d0
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D22
ldda [%l7]ASI_BLK_P, %d16
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D38
ldda [%l7]ASI_BLK_P, %d32
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyout_seg3
0:
FALIGN_D22
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D38
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd6
add %i0, 64, %i0
1:
FALIGN_D38
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D6
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd22
add %i0, 64, %i0
2:
FALIGN_D6
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D22
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd38
add %i0, 64, %i0
copyout_seg4:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D8
ldda [%l7]ASI_BLK_P, %d0
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D24
ldda [%l7]ASI_BLK_P, %d16
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D40
ldda [%l7]ASI_BLK_P, %d32
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyout_seg4
0:
FALIGN_D24
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D40
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd8
add %i0, 64, %i0
1:
FALIGN_D40
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D8
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd24
add %i0, 64, %i0
2:
FALIGN_D8
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D24
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd40
add %i0, 64, %i0
copyout_seg5:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D10
ldda [%l7]ASI_BLK_P, %d0
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D26
ldda [%l7]ASI_BLK_P, %d16
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D42
ldda [%l7]ASI_BLK_P, %d32
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyout_seg5
0:
FALIGN_D26
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D42
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd10
add %i0, 64, %i0
1:
FALIGN_D42
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D10
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd26
add %i0, 64, %i0
2:
FALIGN_D10
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D26
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd42
add %i0, 64, %i0
copyout_seg6:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D12
ldda [%l7]ASI_BLK_P, %d0
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D28
ldda [%l7]ASI_BLK_P, %d16
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D44
ldda [%l7]ASI_BLK_P, %d32
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyout_seg6
0:
FALIGN_D28
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D44
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd12
add %i0, 64, %i0
1:
FALIGN_D44
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D12
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd28
add %i0, 64, %i0
2:
FALIGN_D12
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D28
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd44
add %i0, 64, %i0
copyout_seg7:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D14
ldda [%l7]ASI_BLK_P, %d0
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D30
ldda [%l7]ASI_BLK_P, %d16
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D46
ldda [%l7]ASI_BLK_P, %d32
stda %d48, [%i0]ASI_BLK_AIUS
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyout_seg7
0:
FALIGN_D30
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D46
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd14
add %i0, 64, %i0
1:
FALIGN_D46
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D14
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd30
add %i0, 64, %i0
2:
FALIGN_D14
stda %d48, [%i0]ASI_BLK_AIUS
add %i0, 64, %i0
membar #Sync
FALIGN_D30
stda %d48, [%i0]ASI_BLK_AIUS
ba,pt %ncc, copyout_blkd46
add %i0, 64, %i0
!
! dribble out the last partial block
!
copyout_blkd0:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d0, %d2, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd2:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d2, %d4, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd4:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d4, %d6, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd6:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d6, %d8, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd8:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d8, %d10, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd10:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d10, %d12, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd12:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d12, %d14, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd14:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
fsrc1 %d14, %d0
ba,a,pt %ncc, copyout_blkleft
copyout_blkd16:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d16, %d18, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd18:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d18, %d20, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd20:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d20, %d22, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd22:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d22, %d24, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd24:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d24, %d26, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd26:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d26, %d28, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd28:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d28, %d30, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd30:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
fsrc1 %d30, %d0
ba,a,pt %ncc, copyout_blkleft
copyout_blkd32:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d32, %d34, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd34:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d34, %d36, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd36:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d36, %d38, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd38:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d38, %d40, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd40:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d40, %d42, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd42:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d42, %d44, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd44:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
faligndata %d44, %d46, %d48
stda %d48, [%i0]ASI_USER
add %i0, 8, %i0
copyout_blkd46:
subcc %i4, 8, %i4
blu,pn %ncc, copyout_blkdone
fsrc1 %d46, %d0
copyout_blkleft:
1:
ldd [%l7], %d2
add %l7, 8, %l7
subcc %i4, 8, %i4
faligndata %d0, %d2, %d8
stda %d8, [%i0]ASI_USER
blu,pn %ncc, copyout_blkdone
add %i0, 8, %i0
ldd [%l7], %d0
add %l7, 8, %l7
subcc %i4, 8, %i4
faligndata %d2, %d0, %d8
stda %d8, [%i0]ASI_USER
bgeu,pt %ncc, 1b
add %i0, 8, %i0
copyout_blkdone:
tst %i2
bz,pt %ncc, .copyout_exit
and %l3, 0x4, %l3 ! fprs.du = fprs.dl = 0
7: ldub [%i1], %i4
inc %i1
stba %i4, [%i0]ASI_USER
inc %i0
deccc %i2
bgu %ncc, 7b
nop
.copyout_exit:
membar #StoreLoad|#StoreStore
btst FPUSED_FLAG, SAVED_LOFAULT
bz 1f
nop
ld [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2
wr %o2, 0, %gsr ! restore gsr
ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3
btst FPRS_FEF, %o3
bz 4f
nop
! restore fpregs from stack
membar #Sync
add %fp, STACK_BIAS - 257, %o2
and %o2, -64, %o2
ldda [%o2]ASI_BLK_P, %d0
add %o2, 64, %o2
ldda [%o2]ASI_BLK_P, %d16
add %o2, 64, %o2
ldda [%o2]ASI_BLK_P, %d32
add %o2, 64, %o2
ldda [%o2]ASI_BLK_P, %d48
membar #Sync
ba,pt %ncc, 1f
wr %o3, 0, %fprs ! restore fprs
4:
FZERO ! zero all of the fpregs
wr %o3, 0, %fprs ! restore fprs
1:
andn SAVED_LOFAULT, FPUSED_FLAG, SAVED_LOFAULT
membar #Sync ! sync error barrier
stn SAVED_LOFAULT, [THREAD_REG + T_LOFAULT] ! restore old t_lofault
ret
restore %g0, 0, %o0
.copyout_err:
ldn [THREAD_REG + T_COPYOPS], %o4
brz %o4, 2f
nop
ldn [%o4 + CP_COPYOUT], %g2
jmp %g2
nop
2:
retl
mov -1, %o0
SET_SIZE(copyout)
#endif /* lint */
#ifdef lint
/*ARGSUSED*/
int
xcopyout(const void *kaddr, void *uaddr, size_t count)
{ return (0); }
#else /* lint */
ENTRY(xcopyout)
sethi %hi(.xcopyout_err), REAL_LOFAULT
b .do_copyout
or REAL_LOFAULT, %lo(.xcopyout_err), REAL_LOFAULT
.xcopyout_err:
ldn [THREAD_REG + T_COPYOPS], %o4
brz %o4, 2f
nop
ldn [%o4 + CP_XCOPYOUT], %g2
jmp %g2
nop
2:
retl
mov %g1, %o0
SET_SIZE(xcopyout)
#endif /* lint */
#ifdef lint
/*ARGSUSED*/
int
xcopyout_little(const void *kaddr, void *uaddr, size_t count)
{ return (0); }
#else /* lint */
ENTRY(xcopyout_little)
sethi %hi(.little_err), %o4
ldn [THREAD_REG + T_LOFAULT], %o5
or %o4, %lo(.little_err), %o4
membar #Sync ! sync error barrier
stn %o4, [THREAD_REG + T_LOFAULT]
subcc %g0, %o2, %o3
add %o0, %o2, %o0
bz,pn %ncc, 2f ! check for zero bytes
sub %o2, 1, %o4
add %o1, %o2, %o1
ldub [%o0+%o3], %o4
1: stba %o4, [%o1+%o3]ASI_AIUSL
inccc %o3
sub %o0, 2, %o0 ! get next byte
bcc,a,pt %ncc, 1b
ldub [%o0+%o3], %o4
2: membar #Sync ! sync error barrier
stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault
retl
mov %g0, %o0 ! return (0)
SET_SIZE(xcopyout_little)
#endif /* lint */
/*
* Copy user data to kernel space (copyin/xcopyin/xcopyin_little)
*/
#if defined(lint)
/*ARGSUSED*/
int
copyin(const void *uaddr, void *kaddr, size_t count)
{ return (0); }
#else /* lint */
ENTRY(copyin)
sethi %hi(.copyin_err), REAL_LOFAULT
or REAL_LOFAULT, %lo(.copyin_err), REAL_LOFAULT
.do_copyin:
!
! Check the length and bail if zero.
!
tst %o2
bnz,pt %ncc, 1f
nop
retl
clr %o0
1:
sethi %hi(copyio_fault), %o4
or %o4, %lo(copyio_fault), %o4
sethi %hi(copyio_fault_nowindow), %o3
ldn [THREAD_REG + T_LOFAULT], SAVED_LOFAULT
or %o3, %lo(copyio_fault_nowindow), %o3
membar #Sync
stn %o3, [THREAD_REG + T_LOFAULT]
mov %o0, SAVE_SRC
mov %o1, SAVE_DST
mov %o2, SAVE_COUNT
!
!
!
!
.dcibcp:
!
! pointer. A very fast 4 instruction loop.
!
.align 16
.dcicl:
stb %o4, [%o1 + %o3]
inccc %o3
bl,a,pt %ncc, .dcicl
lduba [%o0 + %o3]ASI_USER, %o4
!
!
!
!
.dci_ns:
!
!
!
! We're single byte aligned.
!
subcc %o2, VIS_COPY_THRESHOLD, %o3
bleu,pt %ncc, .dcibcp
sethi %hi(hw_copy_limit_1), %o3
ld [%o3 + %lo(hw_copy_limit_1)], %o3
!
! Is HW copy on? If not do everything byte for byte.
!
tst %o3
bz,pn %icc, .dcibcp
subcc %o3, %o2, %o3
!
! Are we bigger than the HW limit? If not
! go to byte for byte.
!
bge,pt %ncc, .dcibcp
nop
!
!
.dcih8:
!
!
!
! We're eight byte aligned.
!
subcc %o2, VIS_COPY_THRESHOLD, %o3
bleu,pt %ncc, .dcis8
sethi %hi(hw_copy_limit_8), %o3
ld [%o3 + %lo(hw_copy_limit_8)], %o3
!
! Is HW assist on? If not, do it with the aligned copy.
!
tst %o3
bz,pn %icc, .dcis8
subcc %o3, %o2, %o3
bge %ncc, .dcis8
nop
ba,pt %ncc, .big_copyin
nop
.dcis8:
!
! Housekeeping for copy loops. Uses same idea as in the byte for
! byte copy loop above.
!
add %o0, %o2, %o0
add %o1, %o2, %o1
sub %g0, %o2, %o3
ba,pt %ncc, .didebc
srl %o2, 3, %o2 ! Number of 8 byte chunks to copy
!
! 4 byte aligned?
!
.dcih4:
bnz %ncc, .dcih2
subcc %o2, VIS_COPY_THRESHOLD, %o3
bleu,pt %ncc, .dcis4
sethi %hi(hw_copy_limit_4), %o3
ld [%o3 + %lo(hw_copy_limit_4)], %o3
!
! Is HW assist on? If not, do it with the aligned copy.
!
tst %o3
bz,pn %icc, .dcis4
subcc %o3, %o2, %o3
!
!
.dcis4:
!
!
.dcih2:
!
! We're two byte aligned. Check for "smallness"
! done in delay at .dcih4
!
bleu,pt %ncc, .dcis2
sethi %hi(hw_copy_limit_2), %o3
ld [%o3 + %lo(hw_copy_limit_2)], %o3
!
! Is HW assist on? If not, do it with the aligned copy.
!
tst %o3
bz,pn %icc, .dcis2
subcc %o3, %o2, %o3
!
! Are we larger than the HW limit?
!
bge %ncc, .dcis2
nop
!
!
!
!
.dcis2:
!
!
! code.
!
!
!
!
.align 32
.didebc:
!
!
!
!
!
!
.align 32
.didfbc:
!
!
!
!
!
! copy.
!
.align 32
.didtbc:
!
!
!
!
.dcifh:
!
!
!
! We're going off to do a block copy.
! Switch fault hendlers and grab a window. We
! kernel data to this point.
!
stn %o4, [THREAD_REG + T_LOFAULT]
save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp
!
! %o3 is %i3 after the save...
!
st %i3, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET]
ba,pt %ncc, .do_blockcopyin
wr %g0, FPRS_FEF, %fprs
.copyin_fpregs_inuse:
!
!
!
! We're going off and do a block copy.
! Change to the heavy duty fault handler and grab a window first.
! New handler is passed in
!
stn %o4, [THREAD_REG + T_LOFAULT]
save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp
!
! %o3 is now %i3
!
st %i3, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET]
! save in-use fpregs on stack
wr %g0, FPRS_FEF, %fprs
membar #Sync
add %fp, STACK_BIAS - 257, %o2
and %o2, -64, %o2
stda %d0, [%o2]ASI_BLK_P
add %o2, 64, %o2
stda %d16, [%o2]ASI_BLK_P
add %o2, 64, %o2
stda %d32, [%o2]ASI_BLK_P
add %o2, 64, %o2
stda %d48, [%o2]ASI_BLK_P
membar #Sync
.do_blockcopyin:
membar #StoreStore|#StoreLoad|#LoadStore
rd %gsr, %o2
st %o2, [%fp + STACK_BIAS - SAVED_GSR_OFFSET] ! save gsr
! Set the lower bit in the saved t_lofault to indicate
! that we need to clear the %fprs register on the way
! out
or SAVED_LOFAULT, FPUSED_FLAG, SAVED_LOFAULT
mov %i1, %i5
mov %i0, %i1
mov %i5, %i0
!!! This code is nearly identical to the version in the sun4u
!!! libc_psr. Most bugfixes made to that file should be
!!! merged into this routine.
andcc %i0, 7, %o3
bz copyin_blkcpy
sub %o3, 8, %o3
neg %o3
sub %i2, %o3, %i2
! Align Destination on double-word boundary
2: lduba [%i1]ASI_USER, %o4
inc %i1
inc %i0
deccc %o3
bgu %ncc, 2b
stb %o4, [%i0-1]
copyin_blkcpy:
andcc %i0, 63, %i3
bz,pn %ncc, copyin_blalign ! now block aligned
sub %i3, 64, %i3
neg %i3 ! bytes till block aligned
sub %i2, %i3, %i2 ! update %i2 with new count
! Copy %i3 bytes till dst is block (64 byte) aligned. use
! double word copies.
alignaddr %i1, %g0, %g1
ldda [%g1]ASI_USER, %d0
add %g1, 8, %g1
6:
ldda [%g1]ASI_USER, %d2
add %g1, 8, %g1
subcc %i3, 8, %i3
faligndata %d0, %d2, %d8
std %d8, [%i0]
add %i1, 8, %i1
bz,pn %ncc, copyin_blalign
add %i0, 8, %i0
ldda [%g1]ASI_USER, %d0
add %g1, 8, %g1
subcc %i3, 8, %i3
faligndata %d2, %d0, %d8
std %d8, [%i0]
add %i1, 8, %i1
bgu,pn %ncc, 6b
add %i0, 8, %i0
copyin_blalign:
membar #StoreLoad
! %i2 = total length
! %i3 = blocks (length - 64) / 64
! %i4 = doubles remaining (length - blocks)
sub %i2, 64, %i3
andn %i3, 63, %i3
sub %i2, %i3, %i4
andn %i4, 7, %i4
sub %i4, 16, %i4
sub %i2, %i4, %i2
sub %i2, %i3, %i2
andn %i1, 0x3f, %l7 ! blk aligned address
alignaddr %i1, %g0, %g0 ! gen %gsr
srl %i1, 3, %l5 ! bits 3,4,5 are now least sig in %l5
andcc %l5, 7, %i5 ! mask everything except bits 1,2 3
add %i1, %i4, %i1
add %i1, %i3, %i1
ldda [%l7]ASI_BLK_AIUS, %d0
add %l7, 64, %l7
ldda [%l7]ASI_BLK_AIUS, %d16
add %l7, 64, %l7
ldda [%l7]ASI_BLK_AIUS, %d32
add %l7, 64, %l7
sub %i3, 128, %i3
! switch statement to get us to the right 8 byte blk within a
! 64 byte block
cmp %i5, 4
bgeu,a copyin_hlf
cmp %i5, 6
cmp %i5, 2
bgeu,a copyin_sqtr
nop
cmp %i5, 1
be,a copyin_seg1
nop
ba,pt %ncc, copyin_seg0
nop
copyin_sqtr:
be,a copyin_seg2
nop
ba,pt %ncc, copyin_seg3
nop
copyin_hlf:
bgeu,a copyin_fqtr
nop
cmp %i5, 5
be,a copyin_seg5
nop
ba,pt %ncc, copyin_seg4
nop
copyin_fqtr:
be,a copyin_seg6
nop
ba,pt %ncc, copyin_seg7
nop
copyin_seg0:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D0
ldda [%l7]ASI_BLK_AIUS, %d0
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D16
ldda [%l7]ASI_BLK_AIUS, %d16
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D32
ldda [%l7]ASI_BLK_AIUS, %d32
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyin_seg0
0:
FALIGN_D16
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D32
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd0
add %i0, 64, %i0
1:
FALIGN_D32
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D0
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd16
add %i0, 64, %i0
2:
FALIGN_D0
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D16
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd32
add %i0, 64, %i0
copyin_seg1:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D2
ldda [%l7]ASI_BLK_AIUS, %d0
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D18
ldda [%l7]ASI_BLK_AIUS, %d16
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D34
ldda [%l7]ASI_BLK_AIUS, %d32
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyin_seg1
0:
FALIGN_D18
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D34
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd2
add %i0, 64, %i0
1:
FALIGN_D34
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D2
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd18
add %i0, 64, %i0
2:
FALIGN_D2
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D18
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd34
add %i0, 64, %i0
copyin_seg2:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D4
ldda [%l7]ASI_BLK_AIUS, %d0
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D20
ldda [%l7]ASI_BLK_AIUS, %d16
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D36
ldda [%l7]ASI_BLK_AIUS, %d32
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyin_seg2
0:
FALIGN_D20
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D36
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd4
add %i0, 64, %i0
1:
FALIGN_D36
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D4
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd20
add %i0, 64, %i0
2:
FALIGN_D4
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D20
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd36
add %i0, 64, %i0
copyin_seg3:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D6
ldda [%l7]ASI_BLK_AIUS, %d0
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D22
ldda [%l7]ASI_BLK_AIUS, %d16
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D38
ldda [%l7]ASI_BLK_AIUS, %d32
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyin_seg3
0:
FALIGN_D22
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D38
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd6
add %i0, 64, %i0
1:
FALIGN_D38
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D6
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd22
add %i0, 64, %i0
2:
FALIGN_D6
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D22
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd38
add %i0, 64, %i0
copyin_seg4:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D8
ldda [%l7]ASI_BLK_AIUS, %d0
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D24
ldda [%l7]ASI_BLK_AIUS, %d16
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D40
ldda [%l7]ASI_BLK_AIUS, %d32
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyin_seg4
0:
FALIGN_D24
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D40
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd8
add %i0, 64, %i0
1:
FALIGN_D40
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D8
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd24
add %i0, 64, %i0
2:
FALIGN_D8
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D24
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd40
add %i0, 64, %i0
copyin_seg5:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D10
ldda [%l7]ASI_BLK_AIUS, %d0
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D26
ldda [%l7]ASI_BLK_AIUS, %d16
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D42
ldda [%l7]ASI_BLK_AIUS, %d32
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyin_seg5
0:
FALIGN_D26
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D42
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd10
add %i0, 64, %i0
1:
FALIGN_D42
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D10
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd26
add %i0, 64, %i0
2:
FALIGN_D10
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D26
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd42
add %i0, 64, %i0
copyin_seg6:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D12
ldda [%l7]ASI_BLK_AIUS, %d0
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D28
ldda [%l7]ASI_BLK_AIUS, %d16
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D44
ldda [%l7]ASI_BLK_AIUS, %d32
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyin_seg6
0:
FALIGN_D28
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D44
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd12
add %i0, 64, %i0
1:
FALIGN_D44
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D12
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd28
add %i0, 64, %i0
2:
FALIGN_D12
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D28
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd44
add %i0, 64, %i0
copyin_seg7:
! 1st chunk - %d0 low, %d16 high, %d32 pre, %d48 dst
FALIGN_D14
ldda [%l7]ASI_BLK_AIUS, %d0
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 0f
add %i0, 64, %i0
! 2nd chunk - %d0 pre, %d16 low, %d32 high, %d48 dst
FALIGN_D30
ldda [%l7]ASI_BLK_AIUS, %d16
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 1f
add %i0, 64, %i0
! 3rd chunk - %d0 high, %d16 pre, %d32 low, %d48 dst
FALIGN_D46
ldda [%l7]ASI_BLK_AIUS, %d32
stda %d48, [%i0]ASI_BLK_P
add %l7, 64, %l7
subcc %i3, 64, %i3
bz,pn %ncc, 2f
add %i0, 64, %i0
ba,a,pt %ncc, copyin_seg7
0:
FALIGN_D30
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D46
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd14
add %i0, 64, %i0
1:
FALIGN_D46
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D14
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd30
add %i0, 64, %i0
2:
FALIGN_D14
stda %d48, [%i0]ASI_BLK_P
add %i0, 64, %i0
membar #Sync
FALIGN_D30
stda %d48, [%i0]ASI_BLK_P
ba,pt %ncc, copyin_blkd46
add %i0, 64, %i0
!
! dribble out the last partial block
!
copyin_blkd0:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d0, %d2, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd2:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d2, %d4, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd4:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d4, %d6, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd6:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d6, %d8, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd8:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d8, %d10, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd10:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d10, %d12, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd12:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d12, %d14, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd14:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
fsrc1 %d14, %d0
ba,a,pt %ncc, copyin_blkleft
copyin_blkd16:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d16, %d18, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd18:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d18, %d20, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd20:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d20, %d22, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd22:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d22, %d24, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd24:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d24, %d26, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd26:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d26, %d28, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd28:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d28, %d30, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd30:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
fsrc1 %d30, %d0
ba,a,pt %ncc, copyin_blkleft
copyin_blkd32:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d32, %d34, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd34:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d34, %d36, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd36:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d36, %d38, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd38:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d38, %d40, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd40:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d40, %d42, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd42:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d42, %d44, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd44:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
faligndata %d44, %d46, %d48
std %d48, [%i0]
add %i0, 8, %i0
copyin_blkd46:
subcc %i4, 8, %i4
blu,pn %ncc, copyin_blkdone
fsrc1 %d46, %d0
copyin_blkleft:
1:
ldda [%l7]ASI_USER, %d2
add %l7, 8, %l7
subcc %i4, 8, %i4
faligndata %d0, %d2, %d8
std %d8, [%i0]
blu,pn %ncc, copyin_blkdone
add %i0, 8, %i0
ldda [%l7]ASI_USER, %d0
add %l7, 8, %l7
subcc %i4, 8, %i4
faligndata %d2, %d0, %d8
std %d8, [%i0]
bgeu,pt %ncc, 1b
add %i0, 8, %i0
copyin_blkdone:
tst %i2
bz,pt %ncc, .copyin_exit
and %l3, 0x4, %l3 ! fprs.du = fprs.dl = 0
7: lduba [%i1]ASI_USER, %i4
inc %i1
inc %i0
deccc %i2
bgu %ncc, 7b
stb %i4, [%i0 - 1]
.copyin_exit:
membar #StoreLoad|#StoreStore
btst FPUSED_FLAG, SAVED_LOFAULT
bz %icc, 1f
nop
ld [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 ! restore gsr
wr %o2, 0, %gsr
ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3
btst FPRS_FEF, %o3
bz %icc, 4f
nop
! restore fpregs from stack
membar #Sync
add %fp, STACK_BIAS - 257, %o2
and %o2, -64, %o2
ldda [%o2]ASI_BLK_P, %d0
add %o2, 64, %o2
ldda [%o2]ASI_BLK_P, %d16
add %o2, 64, %o2
ldda [%o2]ASI_BLK_P, %d32
add %o2, 64, %o2
ldda [%o2]ASI_BLK_P, %d48
membar #Sync
ba,pt %ncc, 1f
wr %o3, 0, %fprs ! restore fprs
4:
FZERO ! zero all of the fpregs
wr %o3, 0, %fprs ! restore fprs
1:
andn SAVED_LOFAULT, FPUSED_FLAG, SAVED_LOFAULT
membar #Sync ! sync error barrier
stn SAVED_LOFAULT, [THREAD_REG + T_LOFAULT] ! restore old t_lofault
ret
restore %g0, 0, %o0
.copyin_err:
ldn [THREAD_REG + T_COPYOPS], %o4
brz %o4, 2f
nop
ldn [%o4 + CP_COPYIN], %g2
jmp %g2
nop
2:
retl
mov -1, %o0
SET_SIZE(copyin)
#endif /* lint */
#ifdef lint
/*ARGSUSED*/
int
xcopyin(const void *uaddr, void *kaddr, size_t count)
{ return (0); }
#else /* lint */
ENTRY(xcopyin)
sethi %hi(.xcopyin_err), REAL_LOFAULT
b .do_copyin
or REAL_LOFAULT, %lo(.xcopyin_err), REAL_LOFAULT
.xcopyin_err:
ldn [THREAD_REG + T_COPYOPS], %o4
brz %o4, 2f
nop
ldn [%o4 + CP_XCOPYIN], %g2
jmp %g2
nop
2:
retl
mov %g1, %o0
SET_SIZE(xcopyin)
#endif /* lint */
#ifdef lint
/*ARGSUSED*/
int
xcopyin_little(const void *uaddr, void *kaddr, size_t count)
{ return (0); }
#else /* lint */
ENTRY(xcopyin_little)
sethi %hi(.little_err), %o4
ldn [THREAD_REG + T_LOFAULT], %o5
or %o4, %lo(.little_err), %o4
membar #Sync ! sync error barrier
stn %o4, [THREAD_REG + T_LOFAULT]
subcc %g0, %o2, %o3
add %o0, %o2, %o0
bz,pn %ncc, 2f ! check for zero bytes
sub %o2, 1, %o4
add %o1, %o2, %o1
lduba [%o0+%o3]ASI_AIUSL, %o4
1: stb %o4, [%o1+%o3]
inccc %o3
sub %o0, 2, %o0 ! get next byte
bcc,a,pt %ncc, 1b
lduba [%o0+%o3]ASI_AIUSL, %o4
2: membar #Sync ! sync error barrier
stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault
retl
mov %g0, %o0 ! return (0)
.little_err:
membar #Sync ! sync error barrier
stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault
retl
mov %g1, %o0
SET_SIZE(xcopyin_little)
#endif /* lint */
/*
* Copy a block of storage - must not overlap (from + len <= to).
* No fault handler installed (to be called under on_fault())
*/
#if defined(lint)
/* ARGSUSED */
void
copyin_noerr(const void *ufrom, void *kto, size_t count)
{}
#else /* lint */
ENTRY(copyin_noerr)
sethi %hi(.copyio_noerr), REAL_LOFAULT
b .do_copyin
or REAL_LOFAULT, %lo(.copyio_noerr), REAL_LOFAULT
.copyio_noerr:
jmp SAVED_LOFAULT
nop
SET_SIZE(copyin_noerr)
#endif /* lint */
/*
* Copy a block of storage - must not overlap (from + len <= to).
* No fault handler installed (to be called under on_fault())
*/
#if defined(lint)
/* ARGSUSED */
void
copyout_noerr(const void *kfrom, void *uto, size_t count)
{}
#else /* lint */
ENTRY(copyout_noerr)
sethi %hi(.copyio_noerr), REAL_LOFAULT
b .do_copyout
or REAL_LOFAULT, %lo(.copyio_noerr), REAL_LOFAULT
SET_SIZE(copyout_noerr)
#endif /* lint */
#if defined(lint)
int use_hw_bcopy = 1;
int use_hw_copyio = 1;
int use_hw_bzero = 1;
uint_t hw_copy_limit_1 = 0;
uint_t hw_copy_limit_2 = 0;
uint_t hw_copy_limit_4 = 0;
uint_t hw_copy_limit_8 = 0;
#else /* !lint */
.align 4
DGDEF(use_hw_bcopy)
.word 1
DGDEF(use_hw_copyio)
.word 1
DGDEF(use_hw_bzero)
.word 1
DGDEF(hw_copy_limit_1)
.word 0
DGDEF(hw_copy_limit_2)
.word 0
DGDEF(hw_copy_limit_4)
.word 0
DGDEF(hw_copy_limit_8)
.word 0
.align 64
.section ".text"
#endif /* !lint */
/*
* hwblkclr - clears block-aligned, block-multiple-sized regions that are
*/
#ifdef lint
/*ARGSUSED*/
int
{
return(0);
}
#else /* lint */
bz 1f
.pz_zinst:
bz,a .pz_finished
#endif /* lint */
#ifdef lint
/* Copy 32 bytes of data from src to dst using physical addresses */
/*ARGSUSED*/
void
{}
#else /*!lint */
/*
* Copy 32 bytes of data from src (%o0) to dst (%o1)
* using physical addresses.
*/
#endif /* lint */