1/*
2 * Authors:    Bjorn Wesen (bjornw@axis.com)
3 *	       Hans-Peter Nilsson (hp@axis.com)
4 *
5 */
6#ifndef _CRIS_ARCH_UACCESS_H
7#define _CRIS_ARCH_UACCESS_H
8
9/*
10 * We don't tell gcc that we are accessing memory, but this is OK
11 * because we do not write to any memory gcc knows about, so there
12 * are no aliasing issues.
13 *
14 * Note that PC at a fault is the address *after* the faulting
15 * instruction.
16 */
17#define __put_user_asm(x, addr, err, op)			\
18	__asm__ __volatile__(					\
19		"	"op" %1,[%2]\n"				\
20		"2:\n"						\
21		"	.section .fixup,\"ax\"\n"		\
22		"3:	move.d %3,%0\n"				\
23		"	jump 2b\n"				\
24		"	.previous\n"				\
25		"	.section __ex_table,\"a\"\n"		\
26		"	.dword 2b,3b\n"				\
27		"	.previous\n"				\
28		: "=r" (err)					\
29		: "r" (x), "r" (addr), "g" (-EFAULT), "0" (err))
30
31#define __put_user_asm_64(x, addr, err)				\
32	__asm__ __volatile__(					\
33		"	move.d %M1,[%2]\n"			\
34		"2:	move.d %H1,[%2+4]\n"			\
35		"4:\n"						\
36		"	.section .fixup,\"ax\"\n"		\
37		"3:	move.d %3,%0\n"				\
38		"	jump 4b\n"				\
39		"	.previous\n"				\
40		"	.section __ex_table,\"a\"\n"		\
41		"	.dword 2b,3b\n"				\
42		"	.dword 4b,3b\n"				\
43		"	.previous\n"				\
44		: "=r" (err)					\
45		: "r" (x), "r" (addr), "g" (-EFAULT), "0" (err))
46
47/* See comment before __put_user_asm.  */
48
49#define __get_user_asm(x, addr, err, op)		\
50	__asm__ __volatile__(				\
51		"	"op" [%2],%1\n"			\
52		"2:\n"					\
53		"	.section .fixup,\"ax\"\n"	\
54		"3:	move.d %3,%0\n"			\
55		"	moveq 0,%1\n"			\
56		"	jump 2b\n"			\
57		"	.previous\n"			\
58		"	.section __ex_table,\"a\"\n"	\
59		"	.dword 2b,3b\n"			\
60		"	.previous\n"			\
61		: "=r" (err), "=r" (x)			\
62		: "r" (addr), "g" (-EFAULT), "0" (err))
63
64#define __get_user_asm_64(x, addr, err)			\
65	__asm__ __volatile__(				\
66		"	move.d [%2],%M1\n"		\
67		"2:	move.d [%2+4],%H1\n"		\
68		"4:\n"					\
69		"	.section .fixup,\"ax\"\n"	\
70		"3:	move.d %3,%0\n"			\
71		"	moveq 0,%1\n"			\
72		"	jump 4b\n"			\
73		"	.previous\n"			\
74		"	.section __ex_table,\"a\"\n"	\
75		"	.dword 2b,3b\n"			\
76		"	.dword 4b,3b\n"			\
77		"	.previous\n"			\
78		: "=r" (err), "=r" (x)			\
79		: "r" (addr), "g" (-EFAULT), "0" (err))
80
81/*
82 * Copy a null terminated string from userspace.
83 *
84 * Must return:
85 * -EFAULT		for an exception
86 * count		if we hit the buffer limit
87 * bytes copied		if we hit a null byte
88 * (without the null byte)
89 */
90static inline long
91__do_strncpy_from_user(char *dst, const char *src, long count)
92{
93	long res;
94
95	if (count == 0)
96		return 0;
97
98	/*
99	 * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop.
100	 *  So do we.
101	 *
102	 *  This code is deduced from:
103	 *
104	 *	char tmp2;
105	 *	long tmp1, tmp3
106	 *	tmp1 = count;
107	 *	while ((*dst++ = (tmp2 = *src++)) != 0
108	 *	       && --tmp1)
109	 *	  ;
110	 *
111	 *	res = count - tmp1;
112	 *
113	 *  with tweaks.
114	 */
115
116	__asm__ __volatile__ (
117		"	move.d %3,%0\n"
118		"	move.b [%2+],$r9\n"
119		"1:	beq 2f\n"
120		"	move.b $r9,[%1+]\n"
121
122		"	subq 1,%0\n"
123		"	bne 1b\n"
124		"	move.b [%2+],$r9\n"
125
126		"2:	sub.d %3,%0\n"
127		"	neg.d %0,%0\n"
128		"3:\n"
129		"	.section .fixup,\"ax\"\n"
130		"4:	move.d %7,%0\n"
131		"	jump 3b\n"
132
133		/* There's one address for a fault at the first move, and
134		   two possible PC values for a fault at the second move,
135		   being a delay-slot filler.  However, the branch-target
136		   for the second move is the same as the first address.
137		   Just so you don't get confused...  */
138		"	.previous\n"
139		"	.section __ex_table,\"a\"\n"
140		"	.dword 1b,4b\n"
141		"	.dword 2b,4b\n"
142		"	.previous"
143		: "=r" (res), "=r" (dst), "=r" (src), "=r" (count)
144		: "3" (count), "1" (dst), "2" (src), "g" (-EFAULT)
145		: "r9");
146
147	return res;
148}
149
150/* A few copy asms to build up the more complex ones from.
151
152   Note again, a post-increment is performed regardless of whether a bus
153   fault occurred in that instruction, and PC for a faulted insn is the
154   address *after* the insn.  */
155
156#define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \
157	__asm__ __volatile__ (				\
158			COPY				\
159		"1:\n"					\
160		"	.section .fixup,\"ax\"\n"	\
161			FIXUP				\
162		"	jump 1b\n"			\
163		"	.previous\n"			\
164		"	.section __ex_table,\"a\"\n"	\
165			TENTRY				\
166		"	.previous\n"			\
167		: "=r" (to), "=r" (from), "=r" (ret)	\
168		: "0" (to), "1" (from), "2" (ret)	\
169		: "r9", "memory")
170
171#define __asm_copy_from_user_1(to, from, ret) \
172	__asm_copy_user_cont(to, from, ret,	\
173		"	move.b [%1+],$r9\n"	\
174		"2:	move.b $r9,[%0+]\n",	\
175		"3:	addq 1,%2\n"		\
176		"	clear.b [%0+]\n",	\
177		"	.dword 2b,3b\n")
178
179#define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
180	__asm_copy_user_cont(to, from, ret,		\
181		"	move.w [%1+],$r9\n"		\
182		"2:	move.w $r9,[%0+]\n" COPY,	\
183		"3:	addq 2,%2\n"			\
184		"	clear.w [%0+]\n" FIXUP,		\
185		"	.dword 2b,3b\n" TENTRY)
186
187#define __asm_copy_from_user_2(to, from, ret) \
188	__asm_copy_from_user_2x_cont(to, from, ret, "", "", "")
189
190#define __asm_copy_from_user_3(to, from, ret)		\
191	__asm_copy_from_user_2x_cont(to, from, ret,	\
192		"	move.b [%1+],$r9\n"		\
193		"4:	move.b $r9,[%0+]\n",		\
194		"5:	addq 1,%2\n"			\
195		"	clear.b [%0+]\n",		\
196		"	.dword 4b,5b\n")
197
198#define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
199	__asm_copy_user_cont(to, from, ret,		\
200		"	move.d [%1+],$r9\n"		\
201		"2:	move.d $r9,[%0+]\n" COPY,	\
202		"3:	addq 4,%2\n"			\
203		"	clear.d [%0+]\n" FIXUP,		\
204		"	.dword 2b,3b\n" TENTRY)
205
206#define __asm_copy_from_user_4(to, from, ret) \
207	__asm_copy_from_user_4x_cont(to, from, ret, "", "", "")
208
209#define __asm_copy_from_user_5(to, from, ret) \
210	__asm_copy_from_user_4x_cont(to, from, ret,	\
211		"	move.b [%1+],$r9\n"		\
212		"4:	move.b $r9,[%0+]\n",		\
213		"5:	addq 1,%2\n"			\
214		"	clear.b [%0+]\n",		\
215		"	.dword 4b,5b\n")
216
217#define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
218	__asm_copy_from_user_4x_cont(to, from, ret,	\
219		"	move.w [%1+],$r9\n"		\
220		"4:	move.w $r9,[%0+]\n" COPY,	\
221		"5:	addq 2,%2\n"			\
222		"	clear.w [%0+]\n" FIXUP,		\
223		"	.dword 4b,5b\n" TENTRY)
224
225#define __asm_copy_from_user_6(to, from, ret) \
226	__asm_copy_from_user_6x_cont(to, from, ret, "", "", "")
227
228#define __asm_copy_from_user_7(to, from, ret) \
229	__asm_copy_from_user_6x_cont(to, from, ret,	\
230		"	move.b [%1+],$r9\n"		\
231		"6:	move.b $r9,[%0+]\n",		\
232		"7:	addq 1,%2\n"			\
233		"	clear.b [%0+]\n",		\
234		"	.dword 6b,7b\n")
235
236#define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
237	__asm_copy_from_user_4x_cont(to, from, ret,	\
238		"	move.d [%1+],$r9\n"		\
239		"4:	move.d $r9,[%0+]\n" COPY,	\
240		"5:	addq 4,%2\n"			\
241		"	clear.d [%0+]\n" FIXUP,		\
242		"	.dword 4b,5b\n" TENTRY)
243
244#define __asm_copy_from_user_8(to, from, ret) \
245	__asm_copy_from_user_8x_cont(to, from, ret, "", "", "")
246
247#define __asm_copy_from_user_9(to, from, ret) \
248	__asm_copy_from_user_8x_cont(to, from, ret,	\
249		"	move.b [%1+],$r9\n"		\
250		"6:	move.b $r9,[%0+]\n",		\
251		"7:	addq 1,%2\n"			\
252		"	clear.b [%0+]\n",		\
253		"	.dword 6b,7b\n")
254
255#define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
256	__asm_copy_from_user_8x_cont(to, from, ret,	\
257		"	move.w [%1+],$r9\n"		\
258		"6:	move.w $r9,[%0+]\n" COPY,	\
259		"7:	addq 2,%2\n"			\
260		"	clear.w [%0+]\n" FIXUP,		\
261		"	.dword 6b,7b\n" TENTRY)
262
263#define __asm_copy_from_user_10(to, from, ret) \
264	__asm_copy_from_user_10x_cont(to, from, ret, "", "", "")
265
266#define __asm_copy_from_user_11(to, from, ret)		\
267	__asm_copy_from_user_10x_cont(to, from, ret,	\
268		"	move.b [%1+],$r9\n"		\
269		"8:	move.b $r9,[%0+]\n",		\
270		"9:	addq 1,%2\n"			\
271		"	clear.b [%0+]\n",		\
272		"	.dword 8b,9b\n")
273
274#define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
275	__asm_copy_from_user_8x_cont(to, from, ret,	\
276		"	move.d [%1+],$r9\n"		\
277		"6:	move.d $r9,[%0+]\n" COPY,	\
278		"7:	addq 4,%2\n"			\
279		"	clear.d [%0+]\n" FIXUP,		\
280		"	.dword 6b,7b\n" TENTRY)
281
282#define __asm_copy_from_user_12(to, from, ret) \
283	__asm_copy_from_user_12x_cont(to, from, ret, "", "", "")
284
285#define __asm_copy_from_user_13(to, from, ret) \
286	__asm_copy_from_user_12x_cont(to, from, ret,	\
287		"	move.b [%1+],$r9\n"		\
288		"8:	move.b $r9,[%0+]\n",		\
289		"9:	addq 1,%2\n"			\
290		"	clear.b [%0+]\n",		\
291		"	.dword 8b,9b\n")
292
293#define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
294	__asm_copy_from_user_12x_cont(to, from, ret,	\
295		"	move.w [%1+],$r9\n"		\
296		"8:	move.w $r9,[%0+]\n" COPY,	\
297		"9:	addq 2,%2\n"			\
298		"	clear.w [%0+]\n" FIXUP,		\
299		"	.dword 8b,9b\n" TENTRY)
300
301#define __asm_copy_from_user_14(to, from, ret) \
302	__asm_copy_from_user_14x_cont(to, from, ret, "", "", "")
303
304#define __asm_copy_from_user_15(to, from, ret) \
305	__asm_copy_from_user_14x_cont(to, from, ret,	\
306		"	move.b [%1+],$r9\n"		\
307		"10:	move.b $r9,[%0+]\n",		\
308		"11:	addq 1,%2\n"			\
309		"	clear.b [%0+]\n",		\
310		"	.dword 10b,11b\n")
311
312#define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
313	__asm_copy_from_user_12x_cont(to, from, ret,	\
314		"	move.d [%1+],$r9\n"		\
315		"8:	move.d $r9,[%0+]\n" COPY,	\
316		"9:	addq 4,%2\n"			\
317		"	clear.d [%0+]\n" FIXUP,		\
318		"	.dword 8b,9b\n" TENTRY)
319
320#define __asm_copy_from_user_16(to, from, ret) \
321	__asm_copy_from_user_16x_cont(to, from, ret, "", "", "")
322
323#define __asm_copy_from_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
324	__asm_copy_from_user_16x_cont(to, from, ret,	\
325		"	move.d [%1+],$r9\n"		\
326		"10:	move.d $r9,[%0+]\n" COPY,	\
327		"11:	addq 4,%2\n"			\
328		"	clear.d [%0+]\n" FIXUP,		\
329		"	.dword 10b,11b\n" TENTRY)
330
331#define __asm_copy_from_user_20(to, from, ret) \
332	__asm_copy_from_user_20x_cont(to, from, ret, "", "", "")
333
334#define __asm_copy_from_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
335	__asm_copy_from_user_20x_cont(to, from, ret,	\
336		"	move.d [%1+],$r9\n"		\
337		"12:	move.d $r9,[%0+]\n" COPY,	\
338		"13:	addq 4,%2\n"			\
339		"	clear.d [%0+]\n" FIXUP,		\
340		"	.dword 12b,13b\n" TENTRY)
341
342#define __asm_copy_from_user_24(to, from, ret) \
343	__asm_copy_from_user_24x_cont(to, from, ret, "", "", "")
344
345/* And now, the to-user ones.  */
346
347#define __asm_copy_to_user_1(to, from, ret)	\
348	__asm_copy_user_cont(to, from, ret,	\
349		"	move.b [%1+],$r9\n"	\
350		"	move.b $r9,[%0+]\n2:\n",	\
351		"3:	addq 1,%2\n",		\
352		"	.dword 2b,3b\n")
353
354#define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
355	__asm_copy_user_cont(to, from, ret,		\
356		"	move.w [%1+],$r9\n"		\
357		"	move.w $r9,[%0+]\n2:\n" COPY,	\
358		"3:	addq 2,%2\n" FIXUP,		\
359		"	.dword 2b,3b\n" TENTRY)
360
361#define __asm_copy_to_user_2(to, from, ret) \
362	__asm_copy_to_user_2x_cont(to, from, ret, "", "", "")
363
364#define __asm_copy_to_user_3(to, from, ret) \
365	__asm_copy_to_user_2x_cont(to, from, ret,	\
366		"	move.b [%1+],$r9\n"		\
367		"	move.b $r9,[%0+]\n4:\n",		\
368		"5:	addq 1,%2\n",			\
369		"	.dword 4b,5b\n")
370
371#define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
372	__asm_copy_user_cont(to, from, ret,		\
373		"	move.d [%1+],$r9\n"		\
374		"	move.d $r9,[%0+]\n2:\n" COPY,	\
375		"3:	addq 4,%2\n" FIXUP,		\
376		"	.dword 2b,3b\n" TENTRY)
377
378#define __asm_copy_to_user_4(to, from, ret) \
379	__asm_copy_to_user_4x_cont(to, from, ret, "", "", "")
380
381#define __asm_copy_to_user_5(to, from, ret) \
382	__asm_copy_to_user_4x_cont(to, from, ret,	\
383		"	move.b [%1+],$r9\n"		\
384		"	move.b $r9,[%0+]\n4:\n",		\
385		"5:	addq 1,%2\n",			\
386		"	.dword 4b,5b\n")
387
388#define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
389	__asm_copy_to_user_4x_cont(to, from, ret,	\
390		"	move.w [%1+],$r9\n"		\
391		"	move.w $r9,[%0+]\n4:\n" COPY,	\
392		"5:	addq 2,%2\n" FIXUP,		\
393		"	.dword 4b,5b\n" TENTRY)
394
395#define __asm_copy_to_user_6(to, from, ret) \
396	__asm_copy_to_user_6x_cont(to, from, ret, "", "", "")
397
398#define __asm_copy_to_user_7(to, from, ret) \
399	__asm_copy_to_user_6x_cont(to, from, ret,	\
400		"	move.b [%1+],$r9\n"		\
401		"	move.b $r9,[%0+]\n6:\n",		\
402		"7:	addq 1,%2\n",			\
403		"	.dword 6b,7b\n")
404
405#define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
406	__asm_copy_to_user_4x_cont(to, from, ret,	\
407		"	move.d [%1+],$r9\n"		\
408		"	move.d $r9,[%0+]\n4:\n" COPY,	\
409		"5:	addq 4,%2\n"  FIXUP,		\
410		"	.dword 4b,5b\n" TENTRY)
411
412#define __asm_copy_to_user_8(to, from, ret) \
413	__asm_copy_to_user_8x_cont(to, from, ret, "", "", "")
414
415#define __asm_copy_to_user_9(to, from, ret) \
416	__asm_copy_to_user_8x_cont(to, from, ret,	\
417		"	move.b [%1+],$r9\n"		\
418		"	move.b $r9,[%0+]\n6:\n",		\
419		"7:	addq 1,%2\n",			\
420		"	.dword 6b,7b\n")
421
422#define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
423	__asm_copy_to_user_8x_cont(to, from, ret,	\
424		"	move.w [%1+],$r9\n"		\
425		"	move.w $r9,[%0+]\n6:\n" COPY,	\
426		"7:	addq 2,%2\n" FIXUP,		\
427		"	.dword 6b,7b\n" TENTRY)
428
429#define __asm_copy_to_user_10(to, from, ret) \
430	__asm_copy_to_user_10x_cont(to, from, ret, "", "", "")
431
432#define __asm_copy_to_user_11(to, from, ret) \
433	__asm_copy_to_user_10x_cont(to, from, ret,	\
434		"	move.b [%1+],$r9\n"		\
435		"	move.b $r9,[%0+]\n8:\n",		\
436		"9:	addq 1,%2\n",			\
437		"	.dword 8b,9b\n")
438
439#define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
440	__asm_copy_to_user_8x_cont(to, from, ret,	\
441		"	move.d [%1+],$r9\n"		\
442		"	move.d $r9,[%0+]\n6:\n" COPY,	\
443		"7:	addq 4,%2\n" FIXUP,		\
444		"	.dword 6b,7b\n" TENTRY)
445
446#define __asm_copy_to_user_12(to, from, ret) \
447	__asm_copy_to_user_12x_cont(to, from, ret, "", "", "")
448
449#define __asm_copy_to_user_13(to, from, ret) \
450	__asm_copy_to_user_12x_cont(to, from, ret,	\
451		"	move.b [%1+],$r9\n"		\
452		"	move.b $r9,[%0+]\n8:\n",		\
453		"9:	addq 1,%2\n",			\
454		"	.dword 8b,9b\n")
455
456#define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
457	__asm_copy_to_user_12x_cont(to, from, ret,	\
458		"	move.w [%1+],$r9\n"		\
459		"	move.w $r9,[%0+]\n8:\n" COPY,	\
460		"9:	addq 2,%2\n" FIXUP,		\
461		"	.dword 8b,9b\n" TENTRY)
462
463#define __asm_copy_to_user_14(to, from, ret)	\
464	__asm_copy_to_user_14x_cont(to, from, ret, "", "", "")
465
466#define __asm_copy_to_user_15(to, from, ret) \
467	__asm_copy_to_user_14x_cont(to, from, ret,	\
468		"	move.b [%1+],$r9\n"		\
469		"	move.b $r9,[%0+]\n10:\n",		\
470		"11:	addq 1,%2\n",			\
471		"	.dword 10b,11b\n")
472
473#define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
474	__asm_copy_to_user_12x_cont(to, from, ret,	\
475		"	move.d [%1+],$r9\n"		\
476		"	move.d $r9,[%0+]\n8:\n" COPY,	\
477		"9:	addq 4,%2\n" FIXUP,		\
478		"	.dword 8b,9b\n" TENTRY)
479
480#define __asm_copy_to_user_16(to, from, ret) \
481	__asm_copy_to_user_16x_cont(to, from, ret, "", "", "")
482
483#define __asm_copy_to_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
484	__asm_copy_to_user_16x_cont(to, from, ret,	\
485		"	move.d [%1+],$r9\n"		\
486		"	move.d $r9,[%0+]\n10:\n" COPY,	\
487		"11:	addq 4,%2\n" FIXUP,		\
488		"	.dword 10b,11b\n" TENTRY)
489
490#define __asm_copy_to_user_20(to, from, ret) \
491	__asm_copy_to_user_20x_cont(to, from, ret, "", "", "")
492
493#define __asm_copy_to_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY)	\
494	__asm_copy_to_user_20x_cont(to, from, ret,	\
495		"	move.d [%1+],$r9\n"		\
496		"	move.d $r9,[%0+]\n12:\n" COPY,	\
497		"13:	addq 4,%2\n" FIXUP,		\
498		"	.dword 12b,13b\n" TENTRY)
499
500#define __asm_copy_to_user_24(to, from, ret)	\
501	__asm_copy_to_user_24x_cont(to, from, ret, "", "", "")
502
503/* Define a few clearing asms with exception handlers.  */
504
505/* This frame-asm is like the __asm_copy_user_cont one, but has one less
506   input.  */
507
508#define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \
509	__asm__ __volatile__ (				\
510			CLEAR				\
511		"1:\n"					\
512		"	.section .fixup,\"ax\"\n"	\
513			FIXUP				\
514		"	jump 1b\n"			\
515		"	.previous\n"			\
516		"	.section __ex_table,\"a\"\n"	\
517			TENTRY				\
518		"	.previous"			\
519		: "=r" (to), "=r" (ret)			\
520		: "0" (to), "1" (ret)			\
521		: "memory")
522
523#define __asm_clear_1(to, ret) \
524	__asm_clear(to, ret,			\
525		"	clear.b [%0+]\n2:\n",	\
526		"3:	addq 1,%1\n",		\
527		"	.dword 2b,3b\n")
528
529#define __asm_clear_2(to, ret) \
530	__asm_clear(to, ret,			\
531		"	clear.w [%0+]\n2:\n",	\
532		"3:	addq 2,%1\n",		\
533		"	.dword 2b,3b\n")
534
535#define __asm_clear_3(to, ret) \
536     __asm_clear(to, ret,			\
537		 "	clear.w [%0+]\n"	\
538		 "2:	clear.b [%0+]\n3:\n",	\
539		 "4:	addq 2,%1\n"		\
540		 "5:	addq 1,%1\n",		\
541		 "	.dword 2b,4b\n"		\
542		 "	.dword 3b,5b\n")
543
544#define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
545	__asm_clear(to, ret,				\
546		"	clear.d [%0+]\n2:\n" CLEAR,	\
547		"3:	addq 4,%1\n" FIXUP,		\
548		"	.dword 2b,3b\n" TENTRY)
549
550#define __asm_clear_4(to, ret) \
551	__asm_clear_4x_cont(to, ret, "", "", "")
552
553#define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
554	__asm_clear_4x_cont(to, ret,			\
555		"	clear.d [%0+]\n4:\n" CLEAR,	\
556		"5:	addq 4,%1\n" FIXUP,		\
557		"	.dword 4b,5b\n" TENTRY)
558
559#define __asm_clear_8(to, ret) \
560	__asm_clear_8x_cont(to, ret, "", "", "")
561
562#define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
563	__asm_clear_8x_cont(to, ret,			\
564		"	clear.d [%0+]\n6:\n" CLEAR,	\
565		"7:	addq 4,%1\n" FIXUP,		\
566		"	.dword 6b,7b\n" TENTRY)
567
568#define __asm_clear_12(to, ret) \
569	__asm_clear_12x_cont(to, ret, "", "", "")
570
571#define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
572	__asm_clear_12x_cont(to, ret,			\
573		"	clear.d [%0+]\n8:\n" CLEAR,	\
574		"9:	addq 4,%1\n" FIXUP,		\
575		"	.dword 8b,9b\n" TENTRY)
576
577#define __asm_clear_16(to, ret) \
578	__asm_clear_16x_cont(to, ret, "", "", "")
579
580#define __asm_clear_20x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
581	__asm_clear_16x_cont(to, ret,			\
582		"	clear.d [%0+]\n10:\n" CLEAR,	\
583		"11:	addq 4,%1\n" FIXUP,		\
584		"	.dword 10b,11b\n" TENTRY)
585
586#define __asm_clear_20(to, ret) \
587	__asm_clear_20x_cont(to, ret, "", "", "")
588
589#define __asm_clear_24x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
590	__asm_clear_20x_cont(to, ret,			\
591		"	clear.d [%0+]\n12:\n" CLEAR,	\
592		"13:	addq 4,%1\n" FIXUP,		\
593		"	.dword 12b,13b\n" TENTRY)
594
595#define __asm_clear_24(to, ret) \
596	__asm_clear_24x_cont(to, ret, "", "", "")
597
598/*
599 * Return the size of a string (including the ending 0)
600 *
601 * Return length of string in userspace including terminating 0
602 * or 0 for error.  Return a value greater than N if too long.
603 */
604
605static inline long
606strnlen_user(const char *s, long n)
607{
608	long res, tmp1;
609
610	if (!access_ok(VERIFY_READ, s, 0))
611		return 0;
612
613	/*
614	 * This code is deduced from:
615	 *
616	 *	tmp1 = n;
617	 *	while (tmp1-- > 0 && *s++)
618	 *	  ;
619	 *
620	 *	res = n - tmp1;
621	 *
622	 *  (with tweaks).
623	 */
624
625	__asm__ __volatile__ (
626		"	move.d %1,$r9\n"
627		"0:\n"
628		"	ble 1f\n"
629		"	subq 1,$r9\n"
630
631		"	test.b [%0+]\n"
632		"	bne 0b\n"
633		"	test.d $r9\n"
634		"1:\n"
635		"	move.d %1,%0\n"
636		"	sub.d $r9,%0\n"
637		"2:\n"
638		"	.section .fixup,\"ax\"\n"
639
640		"3:	clear.d %0\n"
641		"	jump 2b\n"
642
643		/* There's one address for a fault at the first move, and
644		   two possible PC values for a fault at the second move,
645		   being a delay-slot filler.  However, the branch-target
646		   for the second move is the same as the first address.
647		   Just so you don't get confused...  */
648		"	.previous\n"
649		"	.section __ex_table,\"a\"\n"
650		"	.dword 0b,3b\n"
651		"	.dword 1b,3b\n"
652		"	.previous\n"
653		: "=r" (res), "=r" (tmp1)
654		: "0" (s), "1" (n)
655		: "r9");
656
657	return res;
658}
659
660#endif
661