1/* copy_in_user.S: Copy from userspace to userspace.
2 *
3 * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
4 */
5
6#include <asm/asi.h>
7
8#define XCC xcc
9
10#define EX(x,y)			\
1198:	x,y;			\
12	.section .fixup;	\
13	.align 4;		\
1499:	retl;			\
15	 mov 1, %o0;		\
16	.section __ex_table,"a";\
17	.align 4;		\
18	.word 98b, 99b;		\
19	.text;			\
20	.align 4;
21
22	.register	%g2,#scratch
23	.register	%g3,#scratch
24
25	.text
26	.align	32
27
28	/* Don't try to get too fancy here, just nice and
29	 * simple.  This is predominantly used for well aligned
30	 * small copies in the compat layer.  It is also used
31	 * to copy register windows around during thread cloning.
32	 */
33
34	.globl		___copy_in_user
35	.type		___copy_in_user,#function
36___copy_in_user:	/* %o0=dst, %o1=src, %o2=len */
37	/* Writing to %asi is _expensive_ so we hardcode it.
38	 * Reading %asi to check for KERNEL_DS is comparatively
39	 * cheap.
40	 */
41	rd		%asi, %g1
42	cmp		%g1, ASI_AIUS
43	bne,pn		%icc, memcpy_user_stub
44	 nop
45
46	cmp		%o2, 0
47	be,pn		%XCC, 85f
48	 or		%o0, %o1, %o3
49	cmp		%o2, 16
50	bleu,a,pn	%XCC, 80f
51	 or		%o3, %o2, %o3
52
53	/* 16 < len <= 64 */
54	andcc		%o3, 0x7, %g0
55	bne,pn		%XCC, 90f
56	 sub		%o0, %o1, %o3
57
58	andn		%o2, 0x7, %o4
59	and		%o2, 0x7, %o2
601:	subcc		%o4, 0x8, %o4
61	EX(ldxa [%o1] %asi, %o5)
62	EX(stxa %o5, [%o1 + %o3] ASI_AIUS)
63	bgu,pt		%XCC, 1b
64	 add		%o1, 0x8, %o1
65	andcc		%o2, 0x4, %g0
66	be,pt		%XCC, 1f
67	 nop
68	sub		%o2, 0x4, %o2
69	EX(lduwa [%o1] %asi, %o5)
70	EX(stwa %o5, [%o1 + %o3] ASI_AIUS)
71	add		%o1, 0x4, %o1
721:	cmp		%o2, 0
73	be,pt		%XCC, 85f
74	 nop
75	ba,pt		%xcc, 90f
76	 nop
77
7880:	/* 0 < len <= 16 */
79	andcc		%o3, 0x3, %g0
80	bne,pn		%XCC, 90f
81	 sub		%o0, %o1, %o3
82
8382:
84	subcc		%o2, 4, %o2
85	EX(lduwa [%o1] %asi, %g1)
86	EX(stwa %g1, [%o1 + %o3] ASI_AIUS)
87	bgu,pt		%XCC, 82b
88	 add		%o1, 4, %o1
89
9085:	retl
91	 clr		%o0
92
93	.align	32
9490:
95	subcc		%o2, 1, %o2
96	EX(lduba [%o1] %asi, %g1)
97	EX(stba %g1, [%o1 + %o3] ASI_AIUS)
98	bgu,pt		%XCC, 90b
99	 add		%o1, 1, %o1
100	retl
101	 clr		%o0
102
103	.size		___copy_in_user, .-___copy_in_user
104
105	/* Act like copy_{to,in}_user(), ie. return zero instead
106	 * of original destination pointer.  This is invoked when
107	 * copy_{to,in}_user() finds that %asi is kernel space.
108	 */
109	.globl		memcpy_user_stub
110	.type		memcpy_user_stub,#function
111memcpy_user_stub:
112	save		%sp, -192, %sp
113	mov		%i0, %o0
114	mov		%i1, %o1
115	call		memcpy
116	 mov		%i2, %o2
117	ret
118	 restore	%g0, %g0, %o0
119	.size		memcpy_user_stub, .-memcpy_user_stub
120