1/*
2 * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2009 PetaLogix
4 * Copyright (C) 2007 LynuxWorks, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License.  See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/errno.h>
12#include <linux/linkage.h>
13#include <asm/page.h>
14
15/*
16 * int __strncpy_user(char *to, char *from, int len);
17 *
18 * Returns:
19 *  -EFAULT  for an exception
20 *  len      if we hit the buffer limit
21 *  bytes copied
22 */
23
24	.text
25.globl __strncpy_user;
26.type  __strncpy_user, @function
27.align 4;
28__strncpy_user:
29
30	/*
31	 * r5 - to
32	 * r6 - from
33	 * r7 - len
34	 * r3 - temp count
35	 * r4 - temp val
36	 */
37	beqid	r7,3f
38	addik	r3,r7,0		/* temp_count = len */
391:
40	lbu	r4,r6,r0
41	sb	r4,r5,r0
42
43	addik	r3,r3,-1
44	beqi	r3,2f		/* break on len */
45
46	addik	r5,r5,1
47	bneid	r4,1b
48	addik	r6,r6,1		/* delay slot */
49	addik	r3,r3,1		/* undo "temp_count--" */
502:
51	rsubk	r3,r3,r7	/* temp_count = len - temp_count */
523:
53	rtsd	r15,8
54	nop
55	.size   __strncpy_user, . - __strncpy_user
56
57	.section	.fixup, "ax"
58	.align	2
594:
60	brid	3b
61	addik	r3,r0, -EFAULT
62
63	.section	__ex_table, "a"
64	.word	1b,4b
65
66/*
67 * int __strnlen_user(char __user *str, int maxlen);
68 *
69 * Returns:
70 *  0 on error
71 *  maxlen + 1  if no NUL byte found within maxlen bytes
72 *  size of the string (including NUL byte)
73 */
74
75	.text
76.globl __strnlen_user;
77.type  __strnlen_user, @function
78.align 4;
79__strnlen_user:
80	beqid	r6,3f
81	addik	r3,r6,0
821:
83	lbu	r4,r5,r0
84	beqid	r4,2f		/* break on NUL */
85	addik	r3,r3,-1	/* delay slot */
86
87	bneid	r3,1b
88	addik	r5,r5,1		/* delay slot */
89
90	addik	r3,r3,-1	/* for break on len */
912:
92	rsubk	r3,r3,r6
933:
94	rtsd	r15,8
95	nop
96	.size   __strnlen_user, . - __strnlen_user
97
98	.section	.fixup,"ax"
994:
100	brid	3b
101	addk	r3,r0,r0
102
103	.section	__ex_table,"a"
104	.word	1b,4b
105
106/* Loop unrolling for __copy_tofrom_user */
107#define COPY(offset)	\
1081:	lwi	r4 , r6, 0x0000 + offset;	\
1092:	lwi	r19, r6, 0x0004 + offset;	\
1103:	lwi	r20, r6, 0x0008 + offset;	\
1114:	lwi	r21, r6, 0x000C + offset;	\
1125:	lwi	r22, r6, 0x0010 + offset;	\
1136:	lwi	r23, r6, 0x0014 + offset;	\
1147:	lwi	r24, r6, 0x0018 + offset;	\
1158:	lwi	r25, r6, 0x001C + offset;	\
1169:	swi	r4 , r5, 0x0000 + offset;	\
11710:	swi	r19, r5, 0x0004 + offset;	\
11811:	swi	r20, r5, 0x0008 + offset;	\
11912:	swi	r21, r5, 0x000C + offset;	\
12013:	swi	r22, r5, 0x0010 + offset;	\
12114:	swi	r23, r5, 0x0014 + offset;	\
12215:	swi	r24, r5, 0x0018 + offset;	\
12316:	swi	r25, r5, 0x001C + offset;	\
124	.section __ex_table,"a";		\
125	.word	1b, 33f;			\
126	.word	2b, 33f;			\
127	.word	3b, 33f;			\
128	.word	4b, 33f;			\
129	.word	5b, 33f;			\
130	.word	6b, 33f;			\
131	.word	7b, 33f;			\
132	.word	8b, 33f;			\
133	.word	9b, 33f;			\
134	.word	10b, 33f;			\
135	.word	11b, 33f;			\
136	.word	12b, 33f;			\
137	.word	13b, 33f;			\
138	.word	14b, 33f;			\
139	.word	15b, 33f;			\
140	.word	16b, 33f;			\
141	.text
142
143#define COPY_80(offset)	\
144	COPY(0x00 + offset);\
145	COPY(0x20 + offset);\
146	COPY(0x40 + offset);\
147	COPY(0x60 + offset);
148
149/*
150 * int __copy_tofrom_user(char *to, char *from, int len)
151 * Return:
152 *   0 on success
153 *   number of not copied bytes on error
154 */
155	.text
156.globl __copy_tofrom_user;
157.type  __copy_tofrom_user, @function
158.align 4;
159__copy_tofrom_user:
160	/*
161	 * r5 - to
162	 * r6 - from
163	 * r7, r3 - count
164	 * r4 - tempval
165	 */
166	beqid	r7, 0f /* zero size is not likely */
167	or	r3, r5, r6 /* find if is any to/from unaligned */
168	or	r3, r3, r7 /* find if count is unaligned */
169	andi	r3, r3, 0x3 /* mask last 3 bits */
170	bneid	r3, bu1 /* if r3 is not zero then byte copying */
171	or	r3, r0, r0
172
173	rsubi	r3, r7, PAGE_SIZE /* detect PAGE_SIZE */
174	beqid	r3, page;
175	or	r3, r0, r0
176
177w1:	lw	r4, r6, r3 /* at least one 4 byte copy */
178w2:	sw	r4, r5, r3
179	addik	r7, r7, -4
180	bneid	r7, w1
181	addik	r3, r3, 4
182	addik	r3, r7, 0
183	rtsd	r15, 8
184	nop
185
186	.section	__ex_table,"a"
187	.word	w1, 0f;
188	.word	w2, 0f;
189	.text
190
191.align 4 /* Alignment is important to keep icache happy */
192page:	/* Create room on stack and save registers for storign values */
193	addik   r1, r1, -40
194	swi	r5, r1, 0
195	swi	r6, r1, 4
196	swi	r7, r1, 8
197	swi	r19, r1, 12
198	swi	r20, r1, 16
199	swi	r21, r1, 20
200	swi	r22, r1, 24
201	swi	r23, r1, 28
202	swi	r24, r1, 32
203	swi	r25, r1, 36
204loop:	/* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */
205	/* Loop unrolling to get performance boost */
206	COPY_80(0x000);
207	COPY_80(0x080);
208	COPY_80(0x100);
209	COPY_80(0x180);
210	/* copy loop */
211	addik   r6, r6, 0x200
212	addik   r7, r7, -0x200
213	bneid   r7, loop
214	addik   r5, r5, 0x200
215
216	/* Restore register content */
217	lwi	r5, r1, 0
218	lwi	r6, r1, 4
219	lwi	r7, r1, 8
220	lwi	r19, r1, 12
221	lwi	r20, r1, 16
222	lwi	r21, r1, 20
223	lwi	r22, r1, 24
224	lwi	r23, r1, 28
225	lwi	r24, r1, 32
226	lwi	r25, r1, 36
227	addik   r1, r1, 40
228	/* return back */
229	addik	r3, r0, 0
230	rtsd	r15, 8
231	nop
232
233/* Fault case - return temp count */
23433:
235	addik	r3, r7, 0
236	/* Restore register content */
237	lwi	r5, r1, 0
238	lwi	r6, r1, 4
239	lwi	r7, r1, 8
240	lwi	r19, r1, 12
241	lwi	r20, r1, 16
242	lwi	r21, r1, 20
243	lwi	r22, r1, 24
244	lwi	r23, r1, 28
245	lwi	r24, r1, 32
246	lwi	r25, r1, 36
247	addik   r1, r1, 40
248	/* return back */
249	rtsd	r15, 8
250	nop
251
252.align 4 /* Alignment is important to keep icache happy */
253bu1:	lbu	r4,r6,r3
254bu2:	sb	r4,r5,r3
255	addik	r7,r7,-1
256	bneid	r7,bu1
257	addik	r3,r3,1		/* delay slot */
2580:
259	addik	r3,r7,0
260	rtsd	r15,8
261	nop
262	.size   __copy_tofrom_user, . - __copy_tofrom_user
263
264	.section	__ex_table,"a"
265	.word	bu1, 0b;
266	.word	bu2, 0b;
267	.text
268