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