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	beqid	r4,2f
42	sb	r4,r5,r0
43
44	addik	r5,r5,1
45	addik	r6,r6,1		/* delay slot */
46
47	addik	r3,r3,-1
48	bnei	r3,1b		/* break on len */
492:
50	rsubk	r3,r3,r7	/* temp_count = len - temp_count */
513:
52	rtsd	r15,8
53	nop
54	.size   __strncpy_user, . - __strncpy_user
55
56	.section	.fixup, "ax"
57	.align	2
584:
59	brid	3b
60	addik	r3,r0, -EFAULT
61
62	.section	__ex_table, "a"
63	.word	1b,4b
64
65/*
66 * int __strnlen_user(char __user *str, int maxlen);
67 *
68 * Returns:
69 *  0 on error
70 *  maxlen + 1  if no NUL byte found within maxlen bytes
71 *  size of the string (including NUL byte)
72 */
73
74	.text
75.globl __strnlen_user;
76.type  __strnlen_user, @function
77.align 4;
78__strnlen_user:
79	beqid	r6,3f
80	addik	r3,r6,0
811:
82	lbu	r4,r5,r0
83	beqid	r4,2f		/* break on NUL */
84	addik	r3,r3,-1	/* delay slot */
85
86	bneid	r3,1b
87	addik	r5,r5,1		/* delay slot */
88
89	addik	r3,r3,-1	/* for break on len */
902:
91	rsubk	r3,r3,r6
923:
93	rtsd	r15,8
94	nop
95	.size   __strnlen_user, . - __strnlen_user
96
97	.section	.fixup,"ax"
984:
99	brid	3b
100	addk	r3,r0,r0
101
102	.section	__ex_table,"a"
103	.word	1b,4b
104
105/* Loop unrolling for __copy_tofrom_user */
106#define COPY(offset)	\
1071:	lwi	r4 , r6, 0x0000 + offset;	\
1082:	lwi	r19, r6, 0x0004 + offset;	\
1093:	lwi	r20, r6, 0x0008 + offset;	\
1104:	lwi	r21, r6, 0x000C + offset;	\
1115:	lwi	r22, r6, 0x0010 + offset;	\
1126:	lwi	r23, r6, 0x0014 + offset;	\
1137:	lwi	r24, r6, 0x0018 + offset;	\
1148:	lwi	r25, r6, 0x001C + offset;	\
1159:	swi	r4 , r5, 0x0000 + offset;	\
11610:	swi	r19, r5, 0x0004 + offset;	\
11711:	swi	r20, r5, 0x0008 + offset;	\
11812:	swi	r21, r5, 0x000C + offset;	\
11913:	swi	r22, r5, 0x0010 + offset;	\
12014:	swi	r23, r5, 0x0014 + offset;	\
12115:	swi	r24, r5, 0x0018 + offset;	\
12216:	swi	r25, r5, 0x001C + offset;	\
123	.section __ex_table,"a";		\
124	.word	1b, 33f;			\
125	.word	2b, 33f;			\
126	.word	3b, 33f;			\
127	.word	4b, 33f;			\
128	.word	5b, 33f;			\
129	.word	6b, 33f;			\
130	.word	7b, 33f;			\
131	.word	8b, 33f;			\
132	.word	9b, 33f;			\
133	.word	10b, 33f;			\
134	.word	11b, 33f;			\
135	.word	12b, 33f;			\
136	.word	13b, 33f;			\
137	.word	14b, 33f;			\
138	.word	15b, 33f;			\
139	.word	16b, 33f;			\
140	.text
141
142#define COPY_80(offset)	\
143	COPY(0x00 + offset);\
144	COPY(0x20 + offset);\
145	COPY(0x40 + offset);\
146	COPY(0x60 + offset);
147
148/*
149 * int __copy_tofrom_user(char *to, char *from, int len)
150 * Return:
151 *   0 on success
152 *   number of not copied bytes on error
153 */
154	.text
155.globl __copy_tofrom_user;
156.type  __copy_tofrom_user, @function
157.align 4;
158__copy_tofrom_user:
159	/*
160	 * r5 - to
161	 * r6 - from
162	 * r7, r3 - count
163	 * r4 - tempval
164	 */
165	beqid	r7, 0f /* zero size is not likely */
166	or	r3, r5, r6 /* find if is any to/from unaligned */
167	or	r3, r3, r7 /* find if count is unaligned */
168	andi	r3, r3, 0x3 /* mask last 3 bits */
169	bneid	r3, bu1 /* if r3 is not zero then byte copying */
170	or	r3, r0, r0
171
172	rsubi	r3, r7, PAGE_SIZE /* detect PAGE_SIZE */
173	beqid	r3, page;
174	or	r3, r0, r0
175
176w1:	lw	r4, r6, r3 /* at least one 4 byte copy */
177w2:	sw	r4, r5, r3
178	addik	r7, r7, -4
179	bneid	r7, w1
180	addik	r3, r3, 4
181	addik	r3, r7, 0
182	rtsd	r15, 8
183	nop
184
185	.section	__ex_table,"a"
186	.word	w1, 0f;
187	.word	w2, 0f;
188	.text
189
190.align 4 /* Alignment is important to keep icache happy */
191page:	/* Create room on stack and save registers for storign values */
192	addik   r1, r1, -40
193	swi	r5, r1, 0
194	swi	r6, r1, 4
195	swi	r7, r1, 8
196	swi	r19, r1, 12
197	swi	r20, r1, 16
198	swi	r21, r1, 20
199	swi	r22, r1, 24
200	swi	r23, r1, 28
201	swi	r24, r1, 32
202	swi	r25, r1, 36
203loop:	/* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */
204	/* Loop unrolling to get performance boost */
205	COPY_80(0x000);
206	COPY_80(0x080);
207	COPY_80(0x100);
208	COPY_80(0x180);
209	/* copy loop */
210	addik   r6, r6, 0x200
211	addik   r7, r7, -0x200
212	bneid   r7, loop
213	addik   r5, r5, 0x200
214
215	/* Restore register content */
216	lwi	r5, r1, 0
217	lwi	r6, r1, 4
218	lwi	r7, r1, 8
219	lwi	r19, r1, 12
220	lwi	r20, r1, 16
221	lwi	r21, r1, 20
222	lwi	r22, r1, 24
223	lwi	r23, r1, 28
224	lwi	r24, r1, 32
225	lwi	r25, r1, 36
226	addik   r1, r1, 40
227	/* return back */
228	addik	r3, r0, 0
229	rtsd	r15, 8
230	nop
231
232/* Fault case - return temp count */
23333:
234	addik	r3, r7, 0
235	/* Restore register content */
236	lwi	r5, r1, 0
237	lwi	r6, r1, 4
238	lwi	r7, r1, 8
239	lwi	r19, r1, 12
240	lwi	r20, r1, 16
241	lwi	r21, r1, 20
242	lwi	r22, r1, 24
243	lwi	r23, r1, 28
244	lwi	r24, r1, 32
245	lwi	r25, r1, 36
246	addik   r1, r1, 40
247	/* return back */
248	rtsd	r15, 8
249	nop
250
251.align 4 /* Alignment is important to keep icache happy */
252bu1:	lbu	r4,r6,r3
253bu2:	sb	r4,r5,r3
254	addik	r7,r7,-1
255	bneid	r7,bu1
256	addik	r3,r3,1		/* delay slot */
2570:
258	addik	r3,r7,0
259	rtsd	r15,8
260	nop
261	.size   __copy_tofrom_user, . - __copy_tofrom_user
262
263	.section	__ex_table,"a"
264	.word	bu1, 0b;
265	.word	bu2, 0b;
266	.text
267