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