xref: /titanic_44/usr/src/uts/sun4/ml/copy.s (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate/*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate/*
23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate#include <sys/param.h>
30*7c478bd9Sstevel@tonic-gate#include <sys/errno.h>
31*7c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h>
32*7c478bd9Sstevel@tonic-gate#include <sys/vtrace.h>
33*7c478bd9Sstevel@tonic-gate#include <sys/machthread.h>
34*7c478bd9Sstevel@tonic-gate#include <sys/clock.h>
35*7c478bd9Sstevel@tonic-gate#include <sys/asi.h>
36*7c478bd9Sstevel@tonic-gate#include <sys/fsr.h>
37*7c478bd9Sstevel@tonic-gate#include <sys/privregs.h>
38*7c478bd9Sstevel@tonic-gate
39*7c478bd9Sstevel@tonic-gate#if !defined(lint)
40*7c478bd9Sstevel@tonic-gate#include "assym.h"
41*7c478bd9Sstevel@tonic-gate#endif	/* lint */
42*7c478bd9Sstevel@tonic-gate
43*7c478bd9Sstevel@tonic-gate/*
44*7c478bd9Sstevel@tonic-gate * Error barrier:
45*7c478bd9Sstevel@tonic-gate * We use membar sync to establish an error barrier for
46*7c478bd9Sstevel@tonic-gate * deferred errors. Membar syncs are added before any update
47*7c478bd9Sstevel@tonic-gate * to t_lofault to ensure that deferred errors from earlier
48*7c478bd9Sstevel@tonic-gate * accesses will not be reported after the membar. This error
49*7c478bd9Sstevel@tonic-gate * isolation is important when we try to recover from async
50*7c478bd9Sstevel@tonic-gate * errors which tries to distinguish kernel accesses to user
51*7c478bd9Sstevel@tonic-gate * data.
52*7c478bd9Sstevel@tonic-gate */
53*7c478bd9Sstevel@tonic-gate
54*7c478bd9Sstevel@tonic-gate/*
55*7c478bd9Sstevel@tonic-gate * Copy a null terminated string from one point to another in
56*7c478bd9Sstevel@tonic-gate * the kernel address space.
57*7c478bd9Sstevel@tonic-gate * NOTE - don't use %o5 in this routine as copy{in,out}str uses it.
58*7c478bd9Sstevel@tonic-gate *
59*7c478bd9Sstevel@tonic-gate * copystr(from, to, maxlength, lencopied)
60*7c478bd9Sstevel@tonic-gate *	caddr_t from, to;
61*7c478bd9Sstevel@tonic-gate *	u_int maxlength, *lencopied;
62*7c478bd9Sstevel@tonic-gate */
63*7c478bd9Sstevel@tonic-gate
64*7c478bd9Sstevel@tonic-gate#if defined(lint)
65*7c478bd9Sstevel@tonic-gate
66*7c478bd9Sstevel@tonic-gate/* ARGSUSED */
67*7c478bd9Sstevel@tonic-gateint
68*7c478bd9Sstevel@tonic-gatecopystr(const char *from, char *to, size_t maxlength, size_t *lencopied)
69*7c478bd9Sstevel@tonic-gate{ return(0); }
70*7c478bd9Sstevel@tonic-gate
71*7c478bd9Sstevel@tonic-gate#else	/* lint */
72*7c478bd9Sstevel@tonic-gate
73*7c478bd9Sstevel@tonic-gate	ENTRY(copystr)
74*7c478bd9Sstevel@tonic-gate	orcc	%o2, %g0, %o4		! save original count
75*7c478bd9Sstevel@tonic-gate	bg,a	%ncc, 1f
76*7c478bd9Sstevel@tonic-gate	  sub	%o0, %o1, %o0		! o0 gets the difference of src and dst
77*7c478bd9Sstevel@tonic-gate
78*7c478bd9Sstevel@tonic-gate	!
79*7c478bd9Sstevel@tonic-gate	! maxlength <= 0
80*7c478bd9Sstevel@tonic-gate	!
81*7c478bd9Sstevel@tonic-gate	bz	%ncc, .cs_out		! maxlength = 0
82*7c478bd9Sstevel@tonic-gate	mov	ENAMETOOLONG, %o0
83*7c478bd9Sstevel@tonic-gate
84*7c478bd9Sstevel@tonic-gate	b	2f			! maxlength < 0
85*7c478bd9Sstevel@tonic-gate	mov	EFAULT, %o0		! return failure
86*7c478bd9Sstevel@tonic-gate
87*7c478bd9Sstevel@tonic-gate	!
88*7c478bd9Sstevel@tonic-gate	! Do a byte by byte loop.
89*7c478bd9Sstevel@tonic-gate	! We do this instead of a word by word copy because most strings
90*7c478bd9Sstevel@tonic-gate	! are small and this takes a small number of cache lines.
91*7c478bd9Sstevel@tonic-gate	!
92*7c478bd9Sstevel@tonic-gate0:
93*7c478bd9Sstevel@tonic-gate	stb	%g1, [%o1]		! store byte
94*7c478bd9Sstevel@tonic-gate	tst	%g1
95*7c478bd9Sstevel@tonic-gate	bnz,pt	%icc, 1f
96*7c478bd9Sstevel@tonic-gate	add	%o1, 1, %o1		! incr dst addr
97*7c478bd9Sstevel@tonic-gate
98*7c478bd9Sstevel@tonic-gate	ba,pt	%ncc, .cs_out		! last byte in string
99*7c478bd9Sstevel@tonic-gate	mov	0, %o0			! ret code = 0
100*7c478bd9Sstevel@tonic-gate1:
101*7c478bd9Sstevel@tonic-gate	subcc	%o2, 1, %o2		! test count
102*7c478bd9Sstevel@tonic-gate	bgeu,a	%ncc, 0b
103*7c478bd9Sstevel@tonic-gate	ldub	[%o0 + %o1], %g1	! delay slot, get source byte
104*7c478bd9Sstevel@tonic-gate
105*7c478bd9Sstevel@tonic-gate	mov	0, %o2			! max number of bytes moved
106*7c478bd9Sstevel@tonic-gate	mov	ENAMETOOLONG, %o0	! ret code = ENAMETOOLONG
107*7c478bd9Sstevel@tonic-gate.cs_out:
108*7c478bd9Sstevel@tonic-gate	tst	%o3
109*7c478bd9Sstevel@tonic-gate	bz	%ncc, 2f
110*7c478bd9Sstevel@tonic-gate	sub	%o4, %o2, %o4		! compute length and store it
111*7c478bd9Sstevel@tonic-gate	stn	%o4, [%o3]
112*7c478bd9Sstevel@tonic-gate2:
113*7c478bd9Sstevel@tonic-gate	retl
114*7c478bd9Sstevel@tonic-gate	nop
115*7c478bd9Sstevel@tonic-gate	SET_SIZE(copystr)
116*7c478bd9Sstevel@tonic-gate
117*7c478bd9Sstevel@tonic-gate#endif	/* lint */
118*7c478bd9Sstevel@tonic-gate
119*7c478bd9Sstevel@tonic-gate
120*7c478bd9Sstevel@tonic-gate/*
121*7c478bd9Sstevel@tonic-gate * Copy a null terminated string from the user address space into
122*7c478bd9Sstevel@tonic-gate * the kernel address space.
123*7c478bd9Sstevel@tonic-gate */
124*7c478bd9Sstevel@tonic-gate#if defined(lint)
125*7c478bd9Sstevel@tonic-gate
126*7c478bd9Sstevel@tonic-gate/* ARGSUSED */
127*7c478bd9Sstevel@tonic-gateint
128*7c478bd9Sstevel@tonic-gatecopyinstr(const char *uaddr, char *kaddr, size_t maxlength,
129*7c478bd9Sstevel@tonic-gate    size_t *lencopied)
130*7c478bd9Sstevel@tonic-gate{ return (0); }
131*7c478bd9Sstevel@tonic-gate
132*7c478bd9Sstevel@tonic-gate#else	/* lint */
133*7c478bd9Sstevel@tonic-gate
134*7c478bd9Sstevel@tonic-gate	ENTRY(copyinstr)
135*7c478bd9Sstevel@tonic-gate	sethi	%hi(.copyinstr_err), %o4
136*7c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_LOFAULT], %o5	! catch faults
137*7c478bd9Sstevel@tonic-gate	or	%o4, %lo(.copyinstr_err), %o4
138*7c478bd9Sstevel@tonic-gate	membar	#Sync				! sync error barrier
139*7c478bd9Sstevel@tonic-gate	stn	%o4, [THREAD_REG + T_LOFAULT]
140*7c478bd9Sstevel@tonic-gate
141*7c478bd9Sstevel@tonic-gate	brz,a,pn %o2, .copyinstr_out
142*7c478bd9Sstevel@tonic-gate	mov	ENAMETOOLONG, %o0
143*7c478bd9Sstevel@tonic-gate
144*7c478bd9Sstevel@tonic-gate	mov	%o2, %g3		! g3 is the current count
145*7c478bd9Sstevel@tonic-gate	mov	%o1, %g4		! g4 is the dest addr
146*7c478bd9Sstevel@tonic-gate
147*7c478bd9Sstevel@tonic-gate	b	1f
148*7c478bd9Sstevel@tonic-gate	sub	%o0, %o1, %g2		! g2 gets the difference of src and dst
149*7c478bd9Sstevel@tonic-gate
150*7c478bd9Sstevel@tonic-gate	!
151*7c478bd9Sstevel@tonic-gate	! Do a byte by byte loop.
152*7c478bd9Sstevel@tonic-gate	! We do this instead of a word by word copy because most strings
153*7c478bd9Sstevel@tonic-gate	! are small and this takes a small number of cache lines.
154*7c478bd9Sstevel@tonic-gate	!
155*7c478bd9Sstevel@tonic-gate0:
156*7c478bd9Sstevel@tonic-gate	stb	%g1, [%g4]		! store byte
157*7c478bd9Sstevel@tonic-gate	tst	%g1
158*7c478bd9Sstevel@tonic-gate	bnz,pt	%icc, 1f
159*7c478bd9Sstevel@tonic-gate	add	%g4, 1, %g4		! incr dst addr
160*7c478bd9Sstevel@tonic-gate
161*7c478bd9Sstevel@tonic-gate	ba,pt	%ncc, .copyinstr_out	! last byte in string
162*7c478bd9Sstevel@tonic-gate	mov	0, %o0			! ret code = 0
163*7c478bd9Sstevel@tonic-gate1:
164*7c478bd9Sstevel@tonic-gate	subcc	%g3, 1, %g3		! test count
165*7c478bd9Sstevel@tonic-gate	bgeu,a	%ncc, 0b
166*7c478bd9Sstevel@tonic-gate	lduba	[%g2+%g4]ASI_USER, %g1	! delay slot, get source byte
167*7c478bd9Sstevel@tonic-gate
168*7c478bd9Sstevel@tonic-gate	mov	0, %g3			! max number of bytes moved
169*7c478bd9Sstevel@tonic-gate	ba,pt	%ncc, .copyinstr_out
170*7c478bd9Sstevel@tonic-gate	  mov	ENAMETOOLONG, %o0	! ret code = ENAMETOOLONG
171*7c478bd9Sstevel@tonic-gate
172*7c478bd9Sstevel@tonic-gate/*
173*7c478bd9Sstevel@tonic-gate * Fault while trying to move from or to user space.
174*7c478bd9Sstevel@tonic-gate * Set and return error code.
175*7c478bd9Sstevel@tonic-gate */
176*7c478bd9Sstevel@tonic-gate.copyinstr_err:
177*7c478bd9Sstevel@tonic-gate	membar	#Sync			! sync error barrier
178*7c478bd9Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LOFAULT]
179*7c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_COPYOPS], %o4
180*7c478bd9Sstevel@tonic-gate	brz	%o4, 1f
181*7c478bd9Sstevel@tonic-gate	nop
182*7c478bd9Sstevel@tonic-gate	ldn	[%o4 + CP_COPYINSTR], %g1
183*7c478bd9Sstevel@tonic-gate	jmp	%g1
184*7c478bd9Sstevel@tonic-gate	nop
185*7c478bd9Sstevel@tonic-gate1:
186*7c478bd9Sstevel@tonic-gate	retl
187*7c478bd9Sstevel@tonic-gate	mov	EFAULT, %o0
188*7c478bd9Sstevel@tonic-gate.copyinstr_out:
189*7c478bd9Sstevel@tonic-gate	tst	%o3			! want length?
190*7c478bd9Sstevel@tonic-gate	bz	%ncc, 2f
191*7c478bd9Sstevel@tonic-gate	sub	%o2, %g3, %o2		! compute length and store it
192*7c478bd9Sstevel@tonic-gate	stn	%o2, [%o3]
193*7c478bd9Sstevel@tonic-gate2:
194*7c478bd9Sstevel@tonic-gate	membar	#Sync			! sync error barrier
195*7c478bd9Sstevel@tonic-gate	retl
196*7c478bd9Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LOFAULT]	! stop catching faults
197*7c478bd9Sstevel@tonic-gate	SET_SIZE(copyinstr)
198*7c478bd9Sstevel@tonic-gate#endif
199*7c478bd9Sstevel@tonic-gate
200*7c478bd9Sstevel@tonic-gate#if defined(lint)
201*7c478bd9Sstevel@tonic-gate
202*7c478bd9Sstevel@tonic-gate/* ARGSUSED */
203*7c478bd9Sstevel@tonic-gateint
204*7c478bd9Sstevel@tonic-gatecopyinstr_noerr(const char *uaddr, char *kaddr, size_t maxlength,
205*7c478bd9Sstevel@tonic-gate    size_t *lencopied)
206*7c478bd9Sstevel@tonic-gate{ return (0); }
207*7c478bd9Sstevel@tonic-gate
208*7c478bd9Sstevel@tonic-gate#else	/* lint */
209*7c478bd9Sstevel@tonic-gate
210*7c478bd9Sstevel@tonic-gate	ENTRY(copyinstr_noerr)
211*7c478bd9Sstevel@tonic-gate	mov	%o2, %o4		! save original count
212*7c478bd9Sstevel@tonic-gate
213*7c478bd9Sstevel@tonic-gate	! maxlength is unsigned so the only error is if it's 0
214*7c478bd9Sstevel@tonic-gate	brz,a,pn %o2, .copyinstr_noerr_out
215*7c478bd9Sstevel@tonic-gate	mov	ENAMETOOLONG, %o0
216*7c478bd9Sstevel@tonic-gate
217*7c478bd9Sstevel@tonic-gate	b	1f
218*7c478bd9Sstevel@tonic-gate	sub	%o0, %o1, %o0		! o0 gets the difference of src and dst
219*7c478bd9Sstevel@tonic-gate
220*7c478bd9Sstevel@tonic-gate	!
221*7c478bd9Sstevel@tonic-gate	! Do a byte by byte loop.
222*7c478bd9Sstevel@tonic-gate	! We do this instead of a word by word copy because most strings
223*7c478bd9Sstevel@tonic-gate	! are small and this takes a small number of cache lines.
224*7c478bd9Sstevel@tonic-gate	!
225*7c478bd9Sstevel@tonic-gate0:
226*7c478bd9Sstevel@tonic-gate	stb	%g1, [%o1]		! store byte
227*7c478bd9Sstevel@tonic-gate	tst	%g1			! null byte?
228*7c478bd9Sstevel@tonic-gate	bnz	1f
229*7c478bd9Sstevel@tonic-gate	add	%o1, 1, %o1		! incr dst addr
230*7c478bd9Sstevel@tonic-gate
231*7c478bd9Sstevel@tonic-gate	ba,pt	%ncc, .copyinstr_noerr_out	! last byte in string
232*7c478bd9Sstevel@tonic-gate	mov	0, %o0			! ret code = 0
233*7c478bd9Sstevel@tonic-gate1:
234*7c478bd9Sstevel@tonic-gate	subcc	%o2, 1, %o2		! test count
235*7c478bd9Sstevel@tonic-gate	bgeu,a	%ncc, 0b
236*7c478bd9Sstevel@tonic-gate	lduba	[%o0 + %o1]ASI_USER, %g1	! delay slot, get source byte
237*7c478bd9Sstevel@tonic-gate
238*7c478bd9Sstevel@tonic-gate	mov	0, %o2			! max number of bytes moved
239*7c478bd9Sstevel@tonic-gate	b	.copyinstr_noerr_out
240*7c478bd9Sstevel@tonic-gate	  mov	ENAMETOOLONG, %o0	! ret code = ENAMETOOLONG
241*7c478bd9Sstevel@tonic-gate.copyinstr_noerr_out:
242*7c478bd9Sstevel@tonic-gate	tst	%o3			! want length?
243*7c478bd9Sstevel@tonic-gate	bz	%ncc, 2f
244*7c478bd9Sstevel@tonic-gate	sub	%o4, %o2, %o4
245*7c478bd9Sstevel@tonic-gate	stn	%o4, [%o3]
246*7c478bd9Sstevel@tonic-gate2:
247*7c478bd9Sstevel@tonic-gate	retl
248*7c478bd9Sstevel@tonic-gate	nop
249*7c478bd9Sstevel@tonic-gate	SET_SIZE(copyinstr_noerr)
250*7c478bd9Sstevel@tonic-gate
251*7c478bd9Sstevel@tonic-gate#endif	/* lint */
252*7c478bd9Sstevel@tonic-gate
253*7c478bd9Sstevel@tonic-gate/*
254*7c478bd9Sstevel@tonic-gate * Copy a null terminated string from the kernel
255*7c478bd9Sstevel@tonic-gate * address space to the user address space.
256*7c478bd9Sstevel@tonic-gate */
257*7c478bd9Sstevel@tonic-gate
258*7c478bd9Sstevel@tonic-gate#if defined(lint)
259*7c478bd9Sstevel@tonic-gate
260*7c478bd9Sstevel@tonic-gate/* ARGSUSED */
261*7c478bd9Sstevel@tonic-gateint
262*7c478bd9Sstevel@tonic-gatecopyoutstr(const char *kaddr, char *uaddr, size_t maxlength,
263*7c478bd9Sstevel@tonic-gate    size_t *lencopied)
264*7c478bd9Sstevel@tonic-gate{ return (0); }
265*7c478bd9Sstevel@tonic-gate
266*7c478bd9Sstevel@tonic-gate#else	/* lint */
267*7c478bd9Sstevel@tonic-gate
268*7c478bd9Sstevel@tonic-gate	ENTRY(copyoutstr)
269*7c478bd9Sstevel@tonic-gate	sethi	%hi(.copyoutstr_err), %o5
270*7c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_LOFAULT], %o4	! catch faults
271*7c478bd9Sstevel@tonic-gate	or	%o5, %lo(.copyoutstr_err), %o5
272*7c478bd9Sstevel@tonic-gate	membar	#Sync				! sync error barrier
273*7c478bd9Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LOFAULT]
274*7c478bd9Sstevel@tonic-gate	mov	%o4, %o5
275*7c478bd9Sstevel@tonic-gate
276*7c478bd9Sstevel@tonic-gate	brz,a,pn %o2, .copyoutstr_out
277*7c478bd9Sstevel@tonic-gate	mov	ENAMETOOLONG, %o0
278*7c478bd9Sstevel@tonic-gate
279*7c478bd9Sstevel@tonic-gate	mov	%o2, %g3		! g3 is the current count
280*7c478bd9Sstevel@tonic-gate	mov	%o1, %g4		! g4 is the dest addr
281*7c478bd9Sstevel@tonic-gate
282*7c478bd9Sstevel@tonic-gate	b	1f
283*7c478bd9Sstevel@tonic-gate	sub	%o0, %o1, %g2		! g2 gets the difference of src and dst
284*7c478bd9Sstevel@tonic-gate
285*7c478bd9Sstevel@tonic-gate	!
286*7c478bd9Sstevel@tonic-gate	! Do a byte by byte loop.
287*7c478bd9Sstevel@tonic-gate	! We do this instead of a word by word copy because most strings
288*7c478bd9Sstevel@tonic-gate	! are small and this takes a small number of cache lines.
289*7c478bd9Sstevel@tonic-gate	!
290*7c478bd9Sstevel@tonic-gate0:
291*7c478bd9Sstevel@tonic-gate	stba	%g1, [%g4]ASI_USER	! store byte
292*7c478bd9Sstevel@tonic-gate	tst	%g1
293*7c478bd9Sstevel@tonic-gate	bnz,pt	%icc, 1f
294*7c478bd9Sstevel@tonic-gate	add	%g4, 1, %g4		! incr dst addr
295*7c478bd9Sstevel@tonic-gate
296*7c478bd9Sstevel@tonic-gate	ba,pt	%ncc, .copyoutstr_out	! last byte in string
297*7c478bd9Sstevel@tonic-gate	mov	0, %o0			! ret code = 0
298*7c478bd9Sstevel@tonic-gate1:
299*7c478bd9Sstevel@tonic-gate	subcc	%g3, 1, %g3		! test count
300*7c478bd9Sstevel@tonic-gate	bgeu,a	%ncc, 0b
301*7c478bd9Sstevel@tonic-gate	ldub	[%g2 + %g4], %g1	! delay slot, get source byte
302*7c478bd9Sstevel@tonic-gate
303*7c478bd9Sstevel@tonic-gate	mov	0, %g3			! max number of bytes moved
304*7c478bd9Sstevel@tonic-gate	ba,pt	%ncc, .copyoutstr_out
305*7c478bd9Sstevel@tonic-gate	  mov	ENAMETOOLONG, %o0	! ret code = ENAMETOOLONG
306*7c478bd9Sstevel@tonic-gate
307*7c478bd9Sstevel@tonic-gate/*
308*7c478bd9Sstevel@tonic-gate * Fault while trying to move from or to user space.
309*7c478bd9Sstevel@tonic-gate * Set and return error code.
310*7c478bd9Sstevel@tonic-gate */
311*7c478bd9Sstevel@tonic-gate.copyoutstr_err:
312*7c478bd9Sstevel@tonic-gate	membar	#Sync			! sync error barrier
313*7c478bd9Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LOFAULT]
314*7c478bd9Sstevel@tonic-gate	ldn	[THREAD_REG + T_COPYOPS], %o4
315*7c478bd9Sstevel@tonic-gate	brz	%o4, 1f
316*7c478bd9Sstevel@tonic-gate	nop
317*7c478bd9Sstevel@tonic-gate	ldn	[%o4 + CP_COPYOUTSTR], %g1
318*7c478bd9Sstevel@tonic-gate	jmp	%g1
319*7c478bd9Sstevel@tonic-gate	nop
320*7c478bd9Sstevel@tonic-gate1:
321*7c478bd9Sstevel@tonic-gate	retl
322*7c478bd9Sstevel@tonic-gate	mov	EFAULT, %o0
323*7c478bd9Sstevel@tonic-gate.copyoutstr_out:
324*7c478bd9Sstevel@tonic-gate	tst	%o3			! want length?
325*7c478bd9Sstevel@tonic-gate	bz	%ncc, 2f
326*7c478bd9Sstevel@tonic-gate	sub	%o2, %g3, %o2		! compute length and store it
327*7c478bd9Sstevel@tonic-gate	stn	%o2, [%o3]
328*7c478bd9Sstevel@tonic-gate2:
329*7c478bd9Sstevel@tonic-gate	membar	#Sync			! sync error barrier
330*7c478bd9Sstevel@tonic-gate	retl
331*7c478bd9Sstevel@tonic-gate	stn	%o5, [THREAD_REG + T_LOFAULT]	! stop catching faults
332*7c478bd9Sstevel@tonic-gate	SET_SIZE(copyoutstr)
333*7c478bd9Sstevel@tonic-gate
334*7c478bd9Sstevel@tonic-gate#endif	/* lint */
335*7c478bd9Sstevel@tonic-gate
336*7c478bd9Sstevel@tonic-gate#if defined(lint)
337*7c478bd9Sstevel@tonic-gate
338*7c478bd9Sstevel@tonic-gate/* ARGSUSED */
339*7c478bd9Sstevel@tonic-gateint
340*7c478bd9Sstevel@tonic-gatecopyoutstr_noerr(const char *kaddr, char *uaddr, size_t maxlength,
341*7c478bd9Sstevel@tonic-gate    size_t *lencopied)
342*7c478bd9Sstevel@tonic-gate{ return (0); }
343*7c478bd9Sstevel@tonic-gate
344*7c478bd9Sstevel@tonic-gate#else	/* lint */
345*7c478bd9Sstevel@tonic-gate
346*7c478bd9Sstevel@tonic-gate	ENTRY(copyoutstr_noerr)
347*7c478bd9Sstevel@tonic-gate	mov	%o2, %o4		! save original count
348*7c478bd9Sstevel@tonic-gate
349*7c478bd9Sstevel@tonic-gate	brz,a,pn %o2, .copyoutstr_noerr_out
350*7c478bd9Sstevel@tonic-gate	mov	ENAMETOOLONG, %o0
351*7c478bd9Sstevel@tonic-gate
352*7c478bd9Sstevel@tonic-gate	b	1f
353*7c478bd9Sstevel@tonic-gate	sub	%o0, %o1, %o0		! o0 gets the difference of src and dst
354*7c478bd9Sstevel@tonic-gate
355*7c478bd9Sstevel@tonic-gate	!
356*7c478bd9Sstevel@tonic-gate	! Do a byte by byte loop.
357*7c478bd9Sstevel@tonic-gate	! We do this instead of a word by word copy because most strings
358*7c478bd9Sstevel@tonic-gate	! are small and this takes a small number of cache lines.
359*7c478bd9Sstevel@tonic-gate	!
360*7c478bd9Sstevel@tonic-gate0:
361*7c478bd9Sstevel@tonic-gate	stba	%g1, [%o1]ASI_USER	! store byte
362*7c478bd9Sstevel@tonic-gate	tst	%g1			! null byte?
363*7c478bd9Sstevel@tonic-gate	bnz	1f
364*7c478bd9Sstevel@tonic-gate	add	%o1, 1, %o1		! incr dst addr
365*7c478bd9Sstevel@tonic-gate
366*7c478bd9Sstevel@tonic-gate	b	.copyoutstr_noerr_out	! last byte in string
367*7c478bd9Sstevel@tonic-gate	mov	0, %o0			! ret code = 0
368*7c478bd9Sstevel@tonic-gate1:
369*7c478bd9Sstevel@tonic-gate	subcc	%o2, 1, %o2		! test count
370*7c478bd9Sstevel@tonic-gate	bgeu,a	%ncc, 0b
371*7c478bd9Sstevel@tonic-gate	ldub	[%o0+%o1], %g1	! delay slot, get source byte
372*7c478bd9Sstevel@tonic-gate
373*7c478bd9Sstevel@tonic-gate	mov	0, %o2			! max number of bytes moved
374*7c478bd9Sstevel@tonic-gate	b	.copyoutstr_noerr_out
375*7c478bd9Sstevel@tonic-gate	  mov	ENAMETOOLONG, %o0	! ret code = ENAMETOOLONG
376*7c478bd9Sstevel@tonic-gate.copyoutstr_noerr_out:
377*7c478bd9Sstevel@tonic-gate	tst	%o3			! want length?
378*7c478bd9Sstevel@tonic-gate	bz	%ncc, 2f
379*7c478bd9Sstevel@tonic-gate	sub	%o4, %o2, %o4
380*7c478bd9Sstevel@tonic-gate	stn	%o4, [%o3]
381*7c478bd9Sstevel@tonic-gate2:
382*7c478bd9Sstevel@tonic-gate	retl
383*7c478bd9Sstevel@tonic-gate	nop
384*7c478bd9Sstevel@tonic-gate	SET_SIZE(copyoutstr_noerr)
385*7c478bd9Sstevel@tonic-gate
386*7c478bd9Sstevel@tonic-gate#endif	/* lint */
387*7c478bd9Sstevel@tonic-gate
388*7c478bd9Sstevel@tonic-gate
389*7c478bd9Sstevel@tonic-gate/*
390*7c478bd9Sstevel@tonic-gate * Copy a block of storage - must not overlap (from + len <= to).
391*7c478bd9Sstevel@tonic-gate * No fault handler installed (to be called under on_fault())
392*7c478bd9Sstevel@tonic-gate */
393*7c478bd9Sstevel@tonic-gate
394*7c478bd9Sstevel@tonic-gate#if defined(lint)
395*7c478bd9Sstevel@tonic-gate
396*7c478bd9Sstevel@tonic-gate/* ARGSUSED */
397*7c478bd9Sstevel@tonic-gatevoid
398*7c478bd9Sstevel@tonic-gateucopy(const void *ufrom, void *uto, size_t ulength)
399*7c478bd9Sstevel@tonic-gate{}
400*7c478bd9Sstevel@tonic-gate
401*7c478bd9Sstevel@tonic-gate#else /* lint */
402*7c478bd9Sstevel@tonic-gate
403*7c478bd9Sstevel@tonic-gate	ENTRY(ucopy)
404*7c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp ! get another window
405*7c478bd9Sstevel@tonic-gate
406*7c478bd9Sstevel@tonic-gate	subcc	%g0, %i2, %i3
407*7c478bd9Sstevel@tonic-gate	add	%i0, %i2, %i0
408*7c478bd9Sstevel@tonic-gate	bz,pn	%ncc, 5f
409*7c478bd9Sstevel@tonic-gate	add	%i1, %i2, %i1
410*7c478bd9Sstevel@tonic-gate	lduba	[%i0 + %i3]ASI_USER, %i4
411*7c478bd9Sstevel@tonic-gate4:	stba	%i4, [%i1 + %i3]ASI_USER
412*7c478bd9Sstevel@tonic-gate	inccc	%i3
413*7c478bd9Sstevel@tonic-gate	bcc,a,pt %ncc, 4b
414*7c478bd9Sstevel@tonic-gate	lduba  [%i0 + %i3]ASI_USER, %i4
415*7c478bd9Sstevel@tonic-gate5:
416*7c478bd9Sstevel@tonic-gate	ret
417*7c478bd9Sstevel@tonic-gate	restore %g0, 0, %o0		! return (0)
418*7c478bd9Sstevel@tonic-gate
419*7c478bd9Sstevel@tonic-gate	SET_SIZE(ucopy)
420*7c478bd9Sstevel@tonic-gate#endif /* lint */
421