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