xref: /onnv-gate/usr/src/uts/sun4u/ml/mach_copy.s (revision 0:68f95e015346)
1*0Sstevel@tonic-gate/*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate/*
23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate#include <sys/param.h>
30*0Sstevel@tonic-gate#include <sys/errno.h>
31*0Sstevel@tonic-gate#include <sys/asm_linkage.h>
32*0Sstevel@tonic-gate#include <sys/vtrace.h>
33*0Sstevel@tonic-gate#include <sys/machthread.h>
34*0Sstevel@tonic-gate#include <sys/clock.h>
35*0Sstevel@tonic-gate#include <sys/asi.h>
36*0Sstevel@tonic-gate#include <sys/fsr.h>
37*0Sstevel@tonic-gate#include <sys/privregs.h>
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gate#if !defined(lint)
40*0Sstevel@tonic-gate#include "assym.h"
41*0Sstevel@tonic-gate#endif	/* lint */
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate#define	FP_USED 1
44*0Sstevel@tonic-gate#define	LOFAULT_SET 2
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gate/*
47*0Sstevel@tonic-gate * Error barrier:
48*0Sstevel@tonic-gate * We use membar sync to establish an error barrier for
49*0Sstevel@tonic-gate * deferred errors. Membar syncs are added before any update
50*0Sstevel@tonic-gate * to t_lofault to ensure that deferred errors from earlier
51*0Sstevel@tonic-gate * accesses will not be reported after the membar. This error
52*0Sstevel@tonic-gate * isolation is important when we try to recover from async
53*0Sstevel@tonic-gate * errors which tries to distinguish kernel accesses to user
54*0Sstevel@tonic-gate * data.
55*0Sstevel@tonic-gate */
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gate/*
58*0Sstevel@tonic-gate * Zero a block of storage.
59*0Sstevel@tonic-gate *
60*0Sstevel@tonic-gate * uzero is used by the kernel to zero a block in user address space.
61*0Sstevel@tonic-gate */
62*0Sstevel@tonic-gate
63*0Sstevel@tonic-gate#if defined(lint)
64*0Sstevel@tonic-gate
65*0Sstevel@tonic-gate/* ARGSUSED */
66*0Sstevel@tonic-gateint
67*0Sstevel@tonic-gatekzero(void *addr, size_t count)
68*0Sstevel@tonic-gate{ return(0); }
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gate/* ARGSUSED */
71*0Sstevel@tonic-gatevoid
72*0Sstevel@tonic-gateuzero(void *addr, size_t count)
73*0Sstevel@tonic-gate{}
74*0Sstevel@tonic-gate
75*0Sstevel@tonic-gate#else	/* lint */
76*0Sstevel@tonic-gate
77*0Sstevel@tonic-gate	ENTRY(uzero)
78*0Sstevel@tonic-gate	!
79*0Sstevel@tonic-gate	! Set a new lo_fault handler only if we came in with one
80*0Sstevel@tonic-gate	! already specified.
81*0Sstevel@tonic-gate	!
82*0Sstevel@tonic-gate	wr	%g0, ASI_USER, %asi
83*0Sstevel@tonic-gate	ldn	[THREAD_REG + T_LOFAULT], %o5
84*0Sstevel@tonic-gate	tst	%o5
85*0Sstevel@tonic-gate	bz,pt	%ncc, .do_zero
86*0Sstevel@tonic-gate	sethi	%hi(.zeroerr), %o2
87*0Sstevel@tonic-gate	or	%o2, %lo(.zeroerr), %o2
88*0Sstevel@tonic-gate	membar	#Sync
89*0Sstevel@tonic-gate	ba,pt	%ncc, .do_zero
90*0Sstevel@tonic-gate	stn	%o2, [THREAD_REG + T_LOFAULT]
91*0Sstevel@tonic-gate
92*0Sstevel@tonic-gate	ENTRY(kzero)
93*0Sstevel@tonic-gate	!
94*0Sstevel@tonic-gate	! Always set a lo_fault handler
95*0Sstevel@tonic-gate	!
96*0Sstevel@tonic-gate	wr	%g0, ASI_P, %asi
97*0Sstevel@tonic-gate	ldn	[THREAD_REG + T_LOFAULT], %o5
98*0Sstevel@tonic-gate	sethi	%hi(.zeroerr), %o2
99*0Sstevel@tonic-gate	or	%o5, LOFAULT_SET, %o5
100*0Sstevel@tonic-gate	or	%o2, %lo(.zeroerr), %o2
101*0Sstevel@tonic-gate	membar	#Sync
102*0Sstevel@tonic-gate	ba,pt	%ncc, .do_zero
103*0Sstevel@tonic-gate	stn	%o2, [THREAD_REG + T_LOFAULT]
104*0Sstevel@tonic-gate
105*0Sstevel@tonic-gate/*
106*0Sstevel@tonic-gate * We got here because of a fault during kzero or if
107*0Sstevel@tonic-gate * uzero or bzero was called with t_lofault non-zero.
108*0Sstevel@tonic-gate * Otherwise we've already run screaming from the room.
109*0Sstevel@tonic-gate * Errno value is in %g1. Note that we're here iff
110*0Sstevel@tonic-gate * we did set t_lofault.
111*0Sstevel@tonic-gate */
112*0Sstevel@tonic-gate.zeroerr:
113*0Sstevel@tonic-gate	!
114*0Sstevel@tonic-gate	! Undo asi register setting. Just set it to be the
115*0Sstevel@tonic-gate        ! kernel default without checking.
116*0Sstevel@tonic-gate	!
117*0Sstevel@tonic-gate	wr	%g0, ASI_P, %asi
118*0Sstevel@tonic-gate	!
119*0Sstevel@tonic-gate	! If saved t_lofault has FP_USED set, clear the %fprs register
120*0Sstevel@tonic-gate	!
121*0Sstevel@tonic-gate	btst	FP_USED, %o5
122*0Sstevel@tonic-gate	bz,pt	%ncc, 1f		! skip if not used
123*0Sstevel@tonic-gate	nop
124*0Sstevel@tonic-gate	membar #Sync
125*0Sstevel@tonic-gate	wr	%g0, %g0, %fprs		! clear fprs
126*0Sstevel@tonic-gate	andn	%o5, FP_USED, %o5	! turn off flag bit
127*0Sstevel@tonic-gate	!
128*0Sstevel@tonic-gate	! We did set t_lofault. It may well have been zero coming in.
129*0Sstevel@tonic-gate	!
130*0Sstevel@tonic-gate1:
131*0Sstevel@tonic-gate	tst	%o5
132*0Sstevel@tonic-gate	membar #Sync
133*0Sstevel@tonic-gate	bne,pn	%ncc, 3f
134*0Sstevel@tonic-gate	andncc	%o5, LOFAULT_SET, %o5
135*0Sstevel@tonic-gate2:
136*0Sstevel@tonic-gate	!
137*0Sstevel@tonic-gate	! Old handler was zero. Just return the error.
138*0Sstevel@tonic-gate	!
139*0Sstevel@tonic-gate	retl				! return
140*0Sstevel@tonic-gate	mov	%g1, %o0		! error code from %g1
141*0Sstevel@tonic-gate3:
142*0Sstevel@tonic-gate	!
143*0Sstevel@tonic-gate	! We're here because %o5 was non-zero. It was non-zero
144*0Sstevel@tonic-gate	! because either LOFAULT_SET was present, a previous fault
145*0Sstevel@tonic-gate	! handler was present or both. In all cases we need to reset
146*0Sstevel@tonic-gate	! T_LOFAULT to the value of %o5 after clearing LOFAULT_SET
147*0Sstevel@tonic-gate	! before we either simply return the error or we invoke the
148*0Sstevel@tonic-gate	! previously specified handler.
149*0Sstevel@tonic-gate	!
150*0Sstevel@tonic-gate	be	%ncc, 2b
151*0Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LOFAULT]
152*0Sstevel@tonic-gate	jmp	%o5			! goto real handler
153*0Sstevel@tonic-gate	  nop
154*0Sstevel@tonic-gate	SET_SIZE(kzero)
155*0Sstevel@tonic-gate	SET_SIZE(uzero)
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate#endif	/* lint */
158*0Sstevel@tonic-gate
159*0Sstevel@tonic-gate/*
160*0Sstevel@tonic-gate * Zero a block of storage.
161*0Sstevel@tonic-gate */
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate#if defined(lint)
164*0Sstevel@tonic-gate
165*0Sstevel@tonic-gate/* ARGSUSED */
166*0Sstevel@tonic-gatevoid
167*0Sstevel@tonic-gatebzero(void *addr, size_t count)
168*0Sstevel@tonic-gate{}
169*0Sstevel@tonic-gate
170*0Sstevel@tonic-gate#else	/* lint */
171*0Sstevel@tonic-gate
172*0Sstevel@tonic-gate	ENTRY(bzero)
173*0Sstevel@tonic-gate	wr	%g0, ASI_P, %asi
174*0Sstevel@tonic-gate
175*0Sstevel@tonic-gate	ldn	[THREAD_REG + T_LOFAULT], %o5	! save old vector
176*0Sstevel@tonic-gate	tst	%o5
177*0Sstevel@tonic-gate	bz,pt	%ncc, .do_zero
178*0Sstevel@tonic-gate	sethi	%hi(.zeroerr), %o2
179*0Sstevel@tonic-gate	or	%o2, %lo(.zeroerr), %o2
180*0Sstevel@tonic-gate	membar	#Sync				! sync error barrier
181*0Sstevel@tonic-gate	stn	%o2, [THREAD_REG + T_LOFAULT]	! install new vector
182*0Sstevel@tonic-gate
183*0Sstevel@tonic-gate.do_zero:
184*0Sstevel@tonic-gate	cmp	%o1, 15			! check for small counts
185*0Sstevel@tonic-gate	blu,pn	%ncc, .byteclr		! just clear bytes
186*0Sstevel@tonic-gate	nop
187*0Sstevel@tonic-gate
188*0Sstevel@tonic-gate	cmp	%o1, 192		! check for large counts
189*0Sstevel@tonic-gate	blu	%ncc, .bzero_small
190*0Sstevel@tonic-gate	nop
191*0Sstevel@tonic-gate
192*0Sstevel@tonic-gate	sethi	%hi(use_hw_bzero), %o2
193*0Sstevel@tonic-gate	ld	[%o2 + %lo(use_hw_bzero)], %o2
194*0Sstevel@tonic-gate	tst	%o2
195*0Sstevel@tonic-gate	bz	%icc, .bzero_small
196*0Sstevel@tonic-gate	nop
197*0Sstevel@tonic-gate
198*0Sstevel@tonic-gate	rd	%fprs, %o2		! check for unused fp
199*0Sstevel@tonic-gate	btst	FPRS_FEF, %o2
200*0Sstevel@tonic-gate	bnz	%icc, .bzero_small
201*0Sstevel@tonic-gate	nop
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate	ldn	[THREAD_REG + T_LWP], %o2
204*0Sstevel@tonic-gate	tst	%o2
205*0Sstevel@tonic-gate	bz,pn	%ncc, .bzero_small
206*0Sstevel@tonic-gate	nop
207*0Sstevel@tonic-gate
208*0Sstevel@tonic-gate	! Check for block alignment
209*0Sstevel@tonic-gate	btst	(64-1), %o0
210*0Sstevel@tonic-gate	bz	%icc, .bzl_block
211*0Sstevel@tonic-gate	nop
212*0Sstevel@tonic-gate
213*0Sstevel@tonic-gate	! Check for double-word alignment
214*0Sstevel@tonic-gate	btst	(8-1), %o0
215*0Sstevel@tonic-gate	bz	%icc, .bzl_dword
216*0Sstevel@tonic-gate	nop
217*0Sstevel@tonic-gate
218*0Sstevel@tonic-gate	! Check for word alignment
219*0Sstevel@tonic-gate	btst	(4-1), %o0
220*0Sstevel@tonic-gate	bz	%icc, .bzl_word
221*0Sstevel@tonic-gate	nop
222*0Sstevel@tonic-gate
223*0Sstevel@tonic-gate	! Clear bytes until word aligned
224*0Sstevel@tonic-gate.bzl_byte:
225*0Sstevel@tonic-gate	stba	%g0, [%o0]%asi
226*0Sstevel@tonic-gate	add	%o0, 1, %o0
227*0Sstevel@tonic-gate	btst	(4-1), %o0
228*0Sstevel@tonic-gate	bnz	%icc, .bzl_byte
229*0Sstevel@tonic-gate	sub	%o1, 1, %o1
230*0Sstevel@tonic-gate
231*0Sstevel@tonic-gate	! Check for dword-aligned
232*0Sstevel@tonic-gate	btst	(8-1), %o0
233*0Sstevel@tonic-gate	bz	%icc, .bzl_dword
234*0Sstevel@tonic-gate	nop
235*0Sstevel@tonic-gate
236*0Sstevel@tonic-gate	! Clear words until double-word aligned
237*0Sstevel@tonic-gate.bzl_word:
238*0Sstevel@tonic-gate	sta	%g0, [%o0]%asi
239*0Sstevel@tonic-gate	add	%o0, 4, %o0
240*0Sstevel@tonic-gate	btst	(8-1), %o0
241*0Sstevel@tonic-gate	bnz	%icc, .bzl_word
242*0Sstevel@tonic-gate	sub	%o1, 4, %o1
243*0Sstevel@tonic-gate
244*0Sstevel@tonic-gate.bzl_dword:
245*0Sstevel@tonic-gate	! Clear dwords until block aligned
246*0Sstevel@tonic-gate	stxa	%g0, [%o0]%asi
247*0Sstevel@tonic-gate	add	%o0, 8, %o0
248*0Sstevel@tonic-gate	btst	(64-1), %o0
249*0Sstevel@tonic-gate	bnz	%icc, .bzl_dword
250*0Sstevel@tonic-gate	sub	%o1, 8, %o1
251*0Sstevel@tonic-gate
252*0Sstevel@tonic-gate.bzl_block:
253*0Sstevel@tonic-gate	membar	#StoreStore|#StoreLoad|#LoadStore
254*0Sstevel@tonic-gate	wr	%g0, FPRS_FEF, %fprs
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate	! Set the lower bit in the saved t_lofault to indicate
257*0Sstevel@tonic-gate	! that we need to clear the %fprs register on the way
258*0Sstevel@tonic-gate	! out
259*0Sstevel@tonic-gate	or	%o5, FP_USED, %o5
260*0Sstevel@tonic-gate
261*0Sstevel@tonic-gate	! Clear block
262*0Sstevel@tonic-gate	fzero	%d0
263*0Sstevel@tonic-gate	fzero	%d2
264*0Sstevel@tonic-gate	fzero	%d4
265*0Sstevel@tonic-gate	fzero	%d6
266*0Sstevel@tonic-gate	fzero	%d8
267*0Sstevel@tonic-gate	fzero	%d10
268*0Sstevel@tonic-gate	fzero	%d12
269*0Sstevel@tonic-gate	fzero	%d14
270*0Sstevel@tonic-gate	rd	%asi, %o3
271*0Sstevel@tonic-gate	wr	%g0, ASI_BLK_P, %asi
272*0Sstevel@tonic-gate	cmp	%o3, ASI_P
273*0Sstevel@tonic-gate	bne,a	%icc, 1f
274*0Sstevel@tonic-gate	wr	%g0, ASI_BLK_AIUS, %asi
275*0Sstevel@tonic-gate1:
276*0Sstevel@tonic-gate	mov	256, %o3
277*0Sstevel@tonic-gate	ba,pt	%ncc, .bzl_doblock
278*0Sstevel@tonic-gate	nop
279*0Sstevel@tonic-gate
280*0Sstevel@tonic-gate.bzl_blkstart:
281*0Sstevel@tonic-gate      ! stda	%d0, [%o0+192]%asi  ! in dly slot of branch that got us here
282*0Sstevel@tonic-gate	stda	%d0, [%o0+128]%asi
283*0Sstevel@tonic-gate	stda	%d0, [%o0+64]%asi
284*0Sstevel@tonic-gate	stda	%d0, [%o0]%asi
285*0Sstevel@tonic-gate.bzl_zinst:
286*0Sstevel@tonic-gate	add	%o0, %o3, %o0
287*0Sstevel@tonic-gate	sub	%o1, %o3, %o1
288*0Sstevel@tonic-gate.bzl_doblock:
289*0Sstevel@tonic-gate	cmp	%o1, 256
290*0Sstevel@tonic-gate	bgeu,a	%ncc, .bzl_blkstart
291*0Sstevel@tonic-gate	stda	%d0, [%o0+192]%asi
292*0Sstevel@tonic-gate
293*0Sstevel@tonic-gate	cmp	%o1, 64
294*0Sstevel@tonic-gate	blu	%ncc, .bzl_finish
295*0Sstevel@tonic-gate
296*0Sstevel@tonic-gate	andn	%o1, (64-1), %o3
297*0Sstevel@tonic-gate	srl	%o3, 4, %o2		! using blocks, 1 instr / 16 words
298*0Sstevel@tonic-gate	set	.bzl_zinst, %o4
299*0Sstevel@tonic-gate	sub	%o4, %o2, %o4
300*0Sstevel@tonic-gate	jmp	%o4
301*0Sstevel@tonic-gate	nop
302*0Sstevel@tonic-gate
303*0Sstevel@tonic-gate.bzl_finish:
304*0Sstevel@tonic-gate	membar	#StoreLoad|#StoreStore
305*0Sstevel@tonic-gate	wr	%g0, %g0, %fprs
306*0Sstevel@tonic-gate	andn	%o5, FP_USED, %o5
307*0Sstevel@tonic-gate
308*0Sstevel@tonic-gate	rd	%asi, %o4
309*0Sstevel@tonic-gate	wr	%g0, ASI_P, %asi
310*0Sstevel@tonic-gate	cmp	%o4, ASI_BLK_P
311*0Sstevel@tonic-gate	bne,a	%icc, 1f
312*0Sstevel@tonic-gate	wr	%g0, ASI_USER, %asi
313*0Sstevel@tonic-gate1:
314*0Sstevel@tonic-gate
315*0Sstevel@tonic-gate.bzlf_dword:
316*0Sstevel@tonic-gate	! double words
317*0Sstevel@tonic-gate	cmp	%o1, 8
318*0Sstevel@tonic-gate	blu	%ncc, .bzlf_word
319*0Sstevel@tonic-gate	nop
320*0Sstevel@tonic-gate	stxa	%g0, [%o0]%asi
321*0Sstevel@tonic-gate	add	%o0, 8, %o0
322*0Sstevel@tonic-gate	sub	%o1, 8, %o1
323*0Sstevel@tonic-gate	ba,pt	%ncc, .bzlf_dword
324*0Sstevel@tonic-gate	nop
325*0Sstevel@tonic-gate
326*0Sstevel@tonic-gate.bzlf_word:
327*0Sstevel@tonic-gate	! words
328*0Sstevel@tonic-gate	cmp	%o1, 4
329*0Sstevel@tonic-gate	blu	%ncc, .bzlf_byte
330*0Sstevel@tonic-gate	nop
331*0Sstevel@tonic-gate	sta	%g0, [%o0]%asi
332*0Sstevel@tonic-gate	add	%o0, 4, %o0
333*0Sstevel@tonic-gate	sub	%o1, 4, %o1
334*0Sstevel@tonic-gate	ba,pt	%ncc, .bzlf_word
335*0Sstevel@tonic-gate	nop
336*0Sstevel@tonic-gate
337*0Sstevel@tonic-gate1:
338*0Sstevel@tonic-gate	add	%o0, 1, %o0		! increment address
339*0Sstevel@tonic-gate.bzlf_byte:
340*0Sstevel@tonic-gate	subcc	%o1, 1, %o1		! decrement count
341*0Sstevel@tonic-gate	bgeu,a	%ncc, 1b
342*0Sstevel@tonic-gate	stba	%g0, [%o0]%asi		! zero a byte
343*0Sstevel@tonic-gate
344*0Sstevel@tonic-gate	!
345*0Sstevel@tonic-gate	! If we used the FP registers, that bit was turned
346*0Sstevel@tonic-gate	! off after we were finished. We're just concerned with
347*0Sstevel@tonic-gate	! whether t_lofault was set when we came in. We end up
348*0Sstevel@tonic-gate	! here from either kzero() or bzero(). kzero() *always*
349*0Sstevel@tonic-gate	! sets a lofault handler. It ors LOFAULT_SET into %o5
350*0Sstevel@tonic-gate	! to indicate it has done this even if the value of %o5
351*0Sstevel@tonic-gate	! is otherwise zero. bzero() sets a lofault handler *only*
352*0Sstevel@tonic-gate	! if one was previously set. Accordingly we need to examine
353*0Sstevel@tonic-gate	! %o5 and if it is non-zero be sure to clear LOFAULT_SET
354*0Sstevel@tonic-gate	! before resetting the error handler.
355*0Sstevel@tonic-gate	!
356*0Sstevel@tonic-gate	tst	%o5
357*0Sstevel@tonic-gate	bz,pt	%ncc, 1f
358*0Sstevel@tonic-gate	andn	%o5, LOFAULT_SET, %o5
359*0Sstevel@tonic-gate	membar	#Sync				! sync error barrier
360*0Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LOFAULT]	! restore old t_lofault
361*0Sstevel@tonic-gate1:
362*0Sstevel@tonic-gate	retl
363*0Sstevel@tonic-gate	clr	%o0			! return (0)
364*0Sstevel@tonic-gate
365*0Sstevel@tonic-gate.bzero_small:
366*0Sstevel@tonic-gate
367*0Sstevel@tonic-gate	!
368*0Sstevel@tonic-gate	! Check for word alignment.
369*0Sstevel@tonic-gate	!
370*0Sstevel@tonic-gate	btst	3, %o0
371*0Sstevel@tonic-gate	bz	.bzero_probe
372*0Sstevel@tonic-gate	mov	0x100, %o3		! constant size of main loop
373*0Sstevel@tonic-gate	!
374*0Sstevel@tonic-gate	!
375*0Sstevel@tonic-gate	! clear bytes until word aligned
376*0Sstevel@tonic-gate	!
377*0Sstevel@tonic-gate1:	stba	%g0,[%o0]%asi
378*0Sstevel@tonic-gate	add	%o0, 1, %o0
379*0Sstevel@tonic-gate	btst	3, %o0
380*0Sstevel@tonic-gate	bnz	1b
381*0Sstevel@tonic-gate	sub	%o1, 1, %o1
382*0Sstevel@tonic-gate.bzero_probe:
383*0Sstevel@tonic-gate
384*0Sstevel@tonic-gate	!
385*0Sstevel@tonic-gate	! if needed move a word to become double-word aligned.
386*0Sstevel@tonic-gate	!
387*0Sstevel@tonic-gate	btst	7, %o0			! is double aligned?
388*0Sstevel@tonic-gate	bz	%icc, .bzero_nobuf
389*0Sstevel@tonic-gate	nop
390*0Sstevel@tonic-gate	sta	%g0, [%o0]%asi		! clr to double boundry
391*0Sstevel@tonic-gate	sub	%o1, 4, %o1
392*0Sstevel@tonic-gate	ba,pt	%ncc, .bzero_nobuf
393*0Sstevel@tonic-gate	add	%o0, 4, %o0
394*0Sstevel@tonic-gate
395*0Sstevel@tonic-gate	!stxa	%g0, [%o0+0xf8]%asi
396*0Sstevel@tonic-gate.bzero_blk:
397*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xf0]%asi
398*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xe8]%asi
399*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xe0]%asi
400*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xd8]%asi
401*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xd0]%asi
402*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xc8]%asi
403*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xc0]%asi
404*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xb8]%asi
405*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xb0]%asi
406*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xa8]%asi
407*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xa0]%asi
408*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x98]%asi
409*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x90]%asi
410*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x88]%asi
411*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x80]%asi
412*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x78]%asi
413*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x70]%asi
414*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x68]%asi
415*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x60]%asi
416*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x58]%asi
417*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x50]%asi
418*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x48]%asi
419*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x40]%asi
420*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x38]%asi
421*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x30]%asi
422*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x28]%asi
423*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x20]%asi
424*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x18]%asi
425*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x10]%asi
426*0Sstevel@tonic-gate	stxa	%g0, [%o0+0x08]%asi
427*0Sstevel@tonic-gate	stxa	%g0, [%o0]%asi
428*0Sstevel@tonic-gate.zinst:
429*0Sstevel@tonic-gate	add	%o0, %o3, %o0		! increment source address
430*0Sstevel@tonic-gate	sub	%o1, %o3, %o1		! decrement count
431*0Sstevel@tonic-gate.bzero_nobuf:
432*0Sstevel@tonic-gate	cmp	%o1, 0x100		! can we do whole chunk?
433*0Sstevel@tonic-gate	bgeu,a	%ncc, .bzero_blk
434*0Sstevel@tonic-gate	stxa	%g0, [%o0+0xf8]%asi	! do first double of chunk
435*0Sstevel@tonic-gate
436*0Sstevel@tonic-gate	cmp	%o1, 7			! can we zero any more double words
437*0Sstevel@tonic-gate	bleu	%ncc, .byteclr		! too small go zero bytes
438*0Sstevel@tonic-gate
439*0Sstevel@tonic-gate	andn	%o1, 7, %o3		! %o3 bytes left, double-word aligned
440*0Sstevel@tonic-gate	srl	%o3, 1, %o2		! using doubles, need 1 instr / 2 words
441*0Sstevel@tonic-gate	set	.zinst, %o4		! address of clr instructions
442*0Sstevel@tonic-gate	sub	%o4, %o2, %o4		! jmp address relative to instr
443*0Sstevel@tonic-gate	jmp	%o4
444*0Sstevel@tonic-gate	nop
445*0Sstevel@tonic-gate	!
446*0Sstevel@tonic-gate	! do leftover bytes
447*0Sstevel@tonic-gate	!
448*0Sstevel@tonic-gate3:
449*0Sstevel@tonic-gate	add	%o0, 1, %o0		! increment address
450*0Sstevel@tonic-gate.byteclr:
451*0Sstevel@tonic-gate	subcc	%o1, 1, %o1		! decrement count
452*0Sstevel@tonic-gate	bgeu,a	%ncc, 3b
453*0Sstevel@tonic-gate	stba	%g0, [%o0]%asi		! zero a byte
454*0Sstevel@tonic-gate
455*0Sstevel@tonic-gate.bzero_finished:
456*0Sstevel@tonic-gate	!
457*0Sstevel@tonic-gate	! We're just concerned with whether t_lofault was set
458*0Sstevel@tonic-gate	! when we came in. We end up here from either kzero()
459*0Sstevel@tonic-gate	! or bzero(). kzero() *always* sets a lofault handler.
460*0Sstevel@tonic-gate	! It ors LOFAULT_SET into %o5 to indicate it has done
461*0Sstevel@tonic-gate	! this even if the value of %o5 is otherwise zero.
462*0Sstevel@tonic-gate	! bzero() sets a lofault handler *only* if one was
463*0Sstevel@tonic-gate	! previously set. Accordingly we need to examine
464*0Sstevel@tonic-gate	! %o5 and if it is non-zero be sure to clear LOFAULT_SET
465*0Sstevel@tonic-gate	! before resetting the error handler.
466*0Sstevel@tonic-gate	!
467*0Sstevel@tonic-gate	tst	%o5
468*0Sstevel@tonic-gate	bz	%ncc, 1f
469*0Sstevel@tonic-gate	andn	%o5, LOFAULT_SET, %o5
470*0Sstevel@tonic-gate	membar	#Sync				! sync error barrier
471*0Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LOFAULT]	! restore old t_lofault
472*0Sstevel@tonic-gate1:
473*0Sstevel@tonic-gate	retl
474*0Sstevel@tonic-gate	clr	%o0			! return (0)
475*0Sstevel@tonic-gate
476*0Sstevel@tonic-gate	SET_SIZE(bzero)
477*0Sstevel@tonic-gate#endif	/* lint */
478