|  | /* | 
|  | * This file is subject to the terms and conditions of the GNU General Public | 
|  | * License.  See the file COPYING in the main directory of this archive | 
|  | * for more details. | 
|  | */ | 
|  |  | 
|  | #include <linux/module.h> | 
|  | #include <asm/uaccess.h> | 
|  |  | 
|  | unsigned long __generic_copy_from_user(void *to, const void __user *from, | 
|  | unsigned long n) | 
|  | { | 
|  | unsigned long tmp, res; | 
|  |  | 
|  | asm volatile ("\n" | 
|  | "	tst.l	%0\n" | 
|  | "	jeq	2f\n" | 
|  | "1:	moves.l	(%1)+,%3\n" | 
|  | "	move.l	%3,(%2)+\n" | 
|  | "	subq.l	#1,%0\n" | 
|  | "	jne	1b\n" | 
|  | "2:	btst	#1,%5\n" | 
|  | "	jeq	4f\n" | 
|  | "3:	moves.w	(%1)+,%3\n" | 
|  | "	move.w	%3,(%2)+\n" | 
|  | "4:	btst	#0,%5\n" | 
|  | "	jeq	6f\n" | 
|  | "5:	moves.b	(%1)+,%3\n" | 
|  | "	move.b  %3,(%2)+\n" | 
|  | "6:\n" | 
|  | "	.section .fixup,\"ax\"\n" | 
|  | "	.even\n" | 
|  | "10:	move.l	%0,%3\n" | 
|  | "7:	clr.l	(%2)+\n" | 
|  | "	subq.l	#1,%3\n" | 
|  | "	jne	7b\n" | 
|  | "	lsl.l	#2,%0\n" | 
|  | "	btst	#1,%5\n" | 
|  | "	jeq	8f\n" | 
|  | "30:	clr.w	(%2)+\n" | 
|  | "	addq.l	#2,%0\n" | 
|  | "8:	btst	#0,%5\n" | 
|  | "	jeq	6b\n" | 
|  | "50:	clr.b	(%2)+\n" | 
|  | "	addq.l	#1,%0\n" | 
|  | "	jra	6b\n" | 
|  | "	.previous\n" | 
|  | "\n" | 
|  | "	.section __ex_table,\"a\"\n" | 
|  | "	.align	4\n" | 
|  | "	.long	1b,10b\n" | 
|  | "	.long	3b,30b\n" | 
|  | "	.long	5b,50b\n" | 
|  | "	.previous" | 
|  | : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) | 
|  | : "0" (n / 4), "d" (n & 3)); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | EXPORT_SYMBOL(__generic_copy_from_user); | 
|  |  | 
|  | unsigned long __generic_copy_to_user(void __user *to, const void *from, | 
|  | unsigned long n) | 
|  | { | 
|  | unsigned long tmp, res; | 
|  |  | 
|  | asm volatile ("\n" | 
|  | "	tst.l	%0\n" | 
|  | "	jeq	4f\n" | 
|  | "1:	move.l	(%1)+,%3\n" | 
|  | "2:	moves.l	%3,(%2)+\n" | 
|  | "3:	subq.l	#1,%0\n" | 
|  | "	jne	1b\n" | 
|  | "4:	btst	#1,%5\n" | 
|  | "	jeq	6f\n" | 
|  | "	move.w	(%1)+,%3\n" | 
|  | "5:	moves.w	%3,(%2)+\n" | 
|  | "6:	btst	#0,%5\n" | 
|  | "	jeq	8f\n" | 
|  | "	move.b	(%1)+,%3\n" | 
|  | "7:	moves.b  %3,(%2)+\n" | 
|  | "8:\n" | 
|  | "	.section .fixup,\"ax\"\n" | 
|  | "	.even\n" | 
|  | "20:	lsl.l	#2,%0\n" | 
|  | "50:	add.l	%5,%0\n" | 
|  | "	jra	8b\n" | 
|  | "	.previous\n" | 
|  | "\n" | 
|  | "	.section __ex_table,\"a\"\n" | 
|  | "	.align	4\n" | 
|  | "	.long	2b,20b\n" | 
|  | "	.long	3b,20b\n" | 
|  | "	.long	5b,50b\n" | 
|  | "	.long	6b,50b\n" | 
|  | "	.long	7b,50b\n" | 
|  | "	.long	8b,50b\n" | 
|  | "	.previous" | 
|  | : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) | 
|  | : "0" (n / 4), "d" (n & 3)); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | EXPORT_SYMBOL(__generic_copy_to_user); | 
|  |  | 
|  | /* | 
|  | * Copy a null terminated string from userspace. | 
|  | */ | 
|  | long strncpy_from_user(char *dst, const char __user *src, long count) | 
|  | { | 
|  | long res; | 
|  | char c; | 
|  |  | 
|  | if (count <= 0) | 
|  | return count; | 
|  |  | 
|  | asm volatile ("\n" | 
|  | "1:	moves.b	(%2)+,%4\n" | 
|  | "	move.b	%4,(%1)+\n" | 
|  | "	jeq	2f\n" | 
|  | "	subq.l	#1,%3\n" | 
|  | "	jne	1b\n" | 
|  | "2:	sub.l	%3,%0\n" | 
|  | "3:\n" | 
|  | "	.section .fixup,\"ax\"\n" | 
|  | "	.even\n" | 
|  | "10:	move.l	%5,%0\n" | 
|  | "	jra	3b\n" | 
|  | "	.previous\n" | 
|  | "\n" | 
|  | "	.section __ex_table,\"a\"\n" | 
|  | "	.align	4\n" | 
|  | "	.long	1b,10b\n" | 
|  | "	.previous" | 
|  | : "=d" (res), "+a" (dst), "+a" (src), "+r" (count), "=&d" (c) | 
|  | : "i" (-EFAULT), "0" (count)); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | EXPORT_SYMBOL(strncpy_from_user); | 
|  |  | 
|  | /* | 
|  | * Return the size of a string (including the ending 0) | 
|  | * | 
|  | * Return 0 on exception, a value greater than N if too long | 
|  | */ | 
|  | long strnlen_user(const char __user *src, long n) | 
|  | { | 
|  | char c; | 
|  | long res; | 
|  |  | 
|  | asm volatile ("\n" | 
|  | "1:	subq.l	#1,%1\n" | 
|  | "	jmi	3f\n" | 
|  | "2:	moves.b	(%0)+,%2\n" | 
|  | "	tst.b	%2\n" | 
|  | "	jne	1b\n" | 
|  | "	jra	4f\n" | 
|  | "\n" | 
|  | "3:	addq.l	#1,%0\n" | 
|  | "4:	sub.l	%4,%0\n" | 
|  | "5:\n" | 
|  | "	.section .fixup,\"ax\"\n" | 
|  | "	.even\n" | 
|  | "20:	sub.l	%0,%0\n" | 
|  | "	jra	5b\n" | 
|  | "	.previous\n" | 
|  | "\n" | 
|  | "	.section __ex_table,\"a\"\n" | 
|  | "	.align	4\n" | 
|  | "	.long	2b,20b\n" | 
|  | "	.previous\n" | 
|  | : "=&a" (res), "+d" (n), "=&d" (c) | 
|  | : "0" (src), "r" (src)); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | EXPORT_SYMBOL(strnlen_user); | 
|  |  | 
|  | /* | 
|  | * Zero Userspace | 
|  | */ | 
|  |  | 
|  | unsigned long __clear_user(void __user *to, unsigned long n) | 
|  | { | 
|  | unsigned long res; | 
|  |  | 
|  | asm volatile ("\n" | 
|  | "	tst.l	%0\n" | 
|  | "	jeq	3f\n" | 
|  | "1:	moves.l	%2,(%1)+\n" | 
|  | "2:	subq.l	#1,%0\n" | 
|  | "	jne	1b\n" | 
|  | "3:	btst	#1,%4\n" | 
|  | "	jeq	5f\n" | 
|  | "4:	moves.w	%2,(%1)+\n" | 
|  | "5:	btst	#0,%4\n" | 
|  | "	jeq	7f\n" | 
|  | "6:	moves.b	%2,(%1)\n" | 
|  | "7:\n" | 
|  | "	.section .fixup,\"ax\"\n" | 
|  | "	.even\n" | 
|  | "10:	lsl.l	#2,%0\n" | 
|  | "40:	add.l	%4,%0\n" | 
|  | "	jra	7b\n" | 
|  | "	.previous\n" | 
|  | "\n" | 
|  | "	.section __ex_table,\"a\"\n" | 
|  | "	.align	4\n" | 
|  | "	.long	1b,10b\n" | 
|  | "	.long	2b,10b\n" | 
|  | "	.long	4b,40b\n" | 
|  | "	.long	5b,40b\n" | 
|  | "	.long	6b,40b\n" | 
|  | "	.long	7b,40b\n" | 
|  | "	.previous" | 
|  | : "=d" (res), "+a" (to) | 
|  | : "r" (0), "0" (n / 4), "d" (n & 3)); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | EXPORT_SYMBOL(__clear_user); |