/*
* 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 2005 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 */
/*
* Error barrier:
* We use membar sync to establish an error barrier for
* deferred errors. Membar syncs are added before any update
* to t_lofault to ensure that deferred errors from earlier
* accesses will not be reported after the membar. This error
* isolation is important when we try to recover from async
* errors which tries to distinguish kernel accesses to user
* data.
*/
/*
* Zero a block of storage.
*
* uzero is used by the kernel to zero a block in user address space.
*/
#if defined(lint)
/* ARGSUSED */
int
{ return(0); }
/* ARGSUSED */
void
{}
#else /* lint */
!
!
!
!
/*
* We got here because of a fault during kzero or if
* uzero or bzero was called with t_lofault non-zero.
* Otherwise we've already run screaming from the room.
* Errno value is in %g1. Note that we're here iff
* we did set t_lofault.
*/
.zeroerr:
!
!
!
!
!
!
1:
2:
!
!
retl ! return
3:
!
! We're here because %o5 was non-zero. It was non-zero
! because either LOFAULT_SET was present, a previous fault
! handler was present or both. In all cases we need to reset
! T_LOFAULT to the value of %o5 after clearing LOFAULT_SET
! before we either simply return the error or we invoke the
! previously specified handler.
!
be %ncc, 2b
stn %o5, [THREAD_REG + T_LOFAULT]
jmp %o5 ! goto real handler
nop
SET_SIZE(kzero)
SET_SIZE(uzero)
#endif /* lint */
/*
* Zero a block of storage.
*/
#if defined(lint)
/* ARGSUSED */
void
bzero(void *addr, size_t count)
{}
#else /* lint */
ENTRY(bzero)
wr %g0, ASI_P, %asi
ldn [THREAD_REG + T_LOFAULT], %o5 ! save old vector
tst %o5
bz,pt %ncc, .do_zero
sethi %hi(.zeroerr), %o2
or %o2, %lo(.zeroerr), %o2
membar #Sync ! sync error barrier
stn %o2, [THREAD_REG + T_LOFAULT] ! install new vector
.do_zero:
cmp %o1, 15 ! check for small counts
blu,pn %ncc, .byteclr ! just clear bytes
nop
cmp %o1, 192 ! check for large counts
blu %ncc, .bzero_small
nop
sethi %hi(use_hw_bzero), %o2
ld [%o2 + %lo(use_hw_bzero)], %o2
tst %o2
bz %icc, .bzero_small
nop
rd %fprs, %o2 ! check for unused fp
btst FPRS_FEF, %o2
bnz %icc, .bzero_small
nop
ldn [THREAD_REG + T_LWP], %o2
tst %o2
bz,pn %ncc, .bzero_small
nop
! Check for block alignment
btst (64-1), %o0
bz %icc, .bzl_block
nop
! Check for double-word alignment
btst (8-1), %o0
bz %icc, .bzl_dword
nop
! Check for word alignment
btst (4-1), %o0
bz %icc, .bzl_word
nop
! Clear bytes until word aligned
.bzl_byte:
stba %g0, [%o0]%asi
add %o0, 1, %o0
btst (4-1), %o0
bnz %icc, .bzl_byte
sub %o1, 1, %o1
! Check for dword-aligned
btst (8-1), %o0
bz %icc, .bzl_dword
nop
! Clear words until double-word aligned
.bzl_word:
sta %g0, [%o0]%asi
add %o0, 4, %o0
btst (8-1), %o0
bnz %icc, .bzl_word
sub %o1, 4, %o1
.bzl_dword:
! Clear dwords until block aligned
stxa %g0, [%o0]%asi
add %o0, 8, %o0
btst (64-1), %o0
bnz %icc, .bzl_dword
sub %o1, 8, %o1
.bzl_block:
membar #StoreStore|#StoreLoad|#LoadStore
wr %g0, FPRS_FEF, %fprs
! Set the lower bit in the saved t_lofault to indicate
! that we need to clear the %fprs register on the way
! out
or %o5, FP_USED, %o5
! Clear block
fzero %d0
fzero %d2
fzero %d4
fzero %d6
fzero %d8
fzero %d10
fzero %d12
fzero %d14
rd %asi, %o3
wr %g0, ASI_BLK_P, %asi
cmp %o3, ASI_P
bne,a %icc, 1f
wr %g0, ASI_BLK_AIUS, %asi
1:
mov 256, %o3
ba,pt %ncc, .bzl_doblock
nop
.bzl_blkstart:
! stda %d0, [%o0+192]%asi ! in dly slot of branch that got us here
stda %d0, [%o0+128]%asi
stda %d0, [%o0+64]%asi
stda %d0, [%o0]%asi
.bzl_zinst:
add %o0, %o3, %o0
sub %o1, %o3, %o1
.bzl_doblock:
cmp %o1, 256
bgeu,a %ncc, .bzl_blkstart
stda %d0, [%o0+192]%asi
cmp %o1, 64
blu %ncc, .bzl_finish
andn %o1, (64-1), %o3
srl %o3, 4, %o2 ! using blocks, 1 instr / 16 words
set .bzl_zinst, %o4
sub %o4, %o2, %o4
jmp %o4
nop
.bzl_finish:
membar #StoreLoad|#StoreStore
wr %g0, %g0, %fprs
andn %o5, FP_USED, %o5
rd %asi, %o4
wr %g0, ASI_P, %asi
cmp %o4, ASI_BLK_P
bne,a %icc, 1f
wr %g0, ASI_USER, %asi
1:
.bzlf_dword:
! double words
cmp %o1, 8
blu %ncc, .bzlf_word
nop
stxa %g0, [%o0]%asi
add %o0, 8, %o0
sub %o1, 8, %o1
ba,pt %ncc, .bzlf_dword
nop
.bzlf_word:
! words
cmp %o1, 4
blu %ncc, .bzlf_byte
nop
sta %g0, [%o0]%asi
add %o0, 4, %o0
sub %o1, 4, %o1
ba,pt %ncc, .bzlf_word
nop
1:
add %o0, 1, %o0 ! increment address
.bzlf_byte:
subcc %o1, 1, %o1 ! decrement count
bgeu,a %ncc, 1b
stba %g0, [%o0]%asi ! zero a byte
!
! If we used the FP registers, that bit was turned
!
1:
!
!
!
!
!
bnz 1b
!
!
.zinst:
!
!
3:
.byteclr:
!
! We're just concerned with whether t_lofault was set
! when we came in. We end up here from either kzero()
! or bzero(). kzero() *always* sets a lofault handler.
! It ors LOFAULT_SET into %o5 to indicate it has done
! this even if the value of %o5 is otherwise zero.
! bzero() sets a lofault handler *only* if one was
! previously set. Accordingly we need to examine
! %o5 and if it is non-zero be sure to clear LOFAULT_SET
! before resetting the error handler.
!
tst %o5
bz %ncc, 1f
andn %o5, LOFAULT_SET, %o5
membar #Sync ! sync error barrier
stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault
1:
retl
clr %o0 ! return (0)
SET_SIZE(bzero)
#endif /* lint */