| Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * This file is subject to the terms and conditions of the GNU General Public | 
|  | 3 | * License.  See the file COPYING in the main directory of this archive | 
|  | 4 | * for more details. | 
|  | 5 | */ | 
|  | 6 |  | 
|  | 7 | #include <linux/module.h> | 
|  | 8 | #include <asm/uaccess.h> | 
|  | 9 |  | 
|  | 10 | unsigned long __generic_copy_from_user(void *to, const void __user *from, | 
|  | 11 | unsigned long n) | 
|  | 12 | { | 
|  | 13 | unsigned long tmp, res; | 
|  | 14 |  | 
|  | 15 | asm volatile ("\n" | 
|  | 16 | "	tst.l	%0\n" | 
|  | 17 | "	jeq	2f\n" | 
|  | 18 | "1:	moves.l	(%1)+,%3\n" | 
|  | 19 | "	move.l	%3,(%2)+\n" | 
|  | 20 | "	subq.l	#1,%0\n" | 
|  | 21 | "	jne	1b\n" | 
|  | 22 | "2:	btst	#1,%5\n" | 
|  | 23 | "	jeq	4f\n" | 
|  | 24 | "3:	moves.w	(%1)+,%3\n" | 
|  | 25 | "	move.w	%3,(%2)+\n" | 
|  | 26 | "4:	btst	#0,%5\n" | 
|  | 27 | "	jeq	6f\n" | 
|  | 28 | "5:	moves.b	(%1)+,%3\n" | 
|  | 29 | "	move.b  %3,(%2)+\n" | 
|  | 30 | "6:\n" | 
|  | 31 | "	.section .fixup,\"ax\"\n" | 
|  | 32 | "	.even\n" | 
|  | 33 | "10:	move.l	%0,%3\n" | 
|  | 34 | "7:	clr.l	(%2)+\n" | 
|  | 35 | "	subq.l	#1,%3\n" | 
|  | 36 | "	jne	7b\n" | 
|  | 37 | "	lsl.l	#2,%0\n" | 
|  | 38 | "	btst	#1,%5\n" | 
|  | 39 | "	jeq	8f\n" | 
|  | 40 | "30:	clr.w	(%2)+\n" | 
|  | 41 | "	addq.l	#2,%0\n" | 
|  | 42 | "8:	btst	#0,%5\n" | 
|  | 43 | "	jeq	6b\n" | 
|  | 44 | "50:	clr.b	(%2)+\n" | 
|  | 45 | "	addq.l	#1,%0\n" | 
|  | 46 | "	jra	6b\n" | 
|  | 47 | "	.previous\n" | 
|  | 48 | "\n" | 
|  | 49 | "	.section __ex_table,\"a\"\n" | 
|  | 50 | "	.align	4\n" | 
|  | 51 | "	.long	1b,10b\n" | 
|  | 52 | "	.long	3b,30b\n" | 
|  | 53 | "	.long	5b,50b\n" | 
|  | 54 | "	.previous" | 
|  | 55 | : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) | 
|  | 56 | : "0" (n / 4), "d" (n & 3)); | 
|  | 57 |  | 
|  | 58 | return res; | 
|  | 59 | } | 
|  | 60 | EXPORT_SYMBOL(__generic_copy_from_user); | 
|  | 61 |  | 
|  | 62 | unsigned long __generic_copy_to_user(void __user *to, const void *from, | 
|  | 63 | unsigned long n) | 
|  | 64 | { | 
|  | 65 | unsigned long tmp, res; | 
|  | 66 |  | 
|  | 67 | asm volatile ("\n" | 
|  | 68 | "	tst.l	%0\n" | 
|  | 69 | "	jeq	4f\n" | 
|  | 70 | "1:	move.l	(%1)+,%3\n" | 
|  | 71 | "2:	moves.l	%3,(%2)+\n" | 
|  | 72 | "3:	subq.l	#1,%0\n" | 
|  | 73 | "	jne	1b\n" | 
|  | 74 | "4:	btst	#1,%5\n" | 
|  | 75 | "	jeq	6f\n" | 
|  | 76 | "	move.w	(%1)+,%3\n" | 
|  | 77 | "5:	moves.w	%3,(%2)+\n" | 
|  | 78 | "6:	btst	#0,%5\n" | 
|  | 79 | "	jeq	8f\n" | 
|  | 80 | "	move.b	(%1)+,%3\n" | 
|  | 81 | "7:	moves.b  %3,(%2)+\n" | 
|  | 82 | "8:\n" | 
|  | 83 | "	.section .fixup,\"ax\"\n" | 
|  | 84 | "	.even\n" | 
|  | 85 | "20:	lsl.l	#2,%0\n" | 
|  | 86 | "50:	add.l	%5,%0\n" | 
| Roman Zippel | 6c04c28 | 2006-10-06 00:43:56 -0700 | [diff] [blame] | 87 | "	jra	8b\n" | 
| Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 88 | "	.previous\n" | 
|  | 89 | "\n" | 
|  | 90 | "	.section __ex_table,\"a\"\n" | 
|  | 91 | "	.align	4\n" | 
|  | 92 | "	.long	2b,20b\n" | 
|  | 93 | "	.long	3b,20b\n" | 
|  | 94 | "	.long	5b,50b\n" | 
|  | 95 | "	.long	6b,50b\n" | 
|  | 96 | "	.long	7b,50b\n" | 
|  | 97 | "	.long	8b,50b\n" | 
|  | 98 | "	.previous" | 
|  | 99 | : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) | 
|  | 100 | : "0" (n / 4), "d" (n & 3)); | 
|  | 101 |  | 
|  | 102 | return res; | 
|  | 103 | } | 
|  | 104 | EXPORT_SYMBOL(__generic_copy_to_user); | 
|  | 105 |  | 
|  | 106 | /* | 
|  | 107 | * Copy a null terminated string from userspace. | 
|  | 108 | */ | 
|  | 109 | long strncpy_from_user(char *dst, const char __user *src, long count) | 
|  | 110 | { | 
|  | 111 | long res; | 
|  | 112 | char c; | 
|  | 113 |  | 
|  | 114 | if (count <= 0) | 
|  | 115 | return count; | 
|  | 116 |  | 
|  | 117 | asm volatile ("\n" | 
|  | 118 | "1:	moves.b	(%2)+,%4\n" | 
|  | 119 | "	move.b	%4,(%1)+\n" | 
|  | 120 | "	jeq	2f\n" | 
|  | 121 | "	subq.l	#1,%3\n" | 
|  | 122 | "	jne	1b\n" | 
|  | 123 | "2:	sub.l	%3,%0\n" | 
|  | 124 | "3:\n" | 
|  | 125 | "	.section .fixup,\"ax\"\n" | 
|  | 126 | "	.even\n" | 
|  | 127 | "10:	move.l	%5,%0\n" | 
|  | 128 | "	jra	3b\n" | 
|  | 129 | "	.previous\n" | 
|  | 130 | "\n" | 
|  | 131 | "	.section __ex_table,\"a\"\n" | 
|  | 132 | "	.align	4\n" | 
|  | 133 | "	.long	1b,10b\n" | 
|  | 134 | "	.previous" | 
|  | 135 | : "=d" (res), "+a" (dst), "+a" (src), "+r" (count), "=&d" (c) | 
|  | 136 | : "i" (-EFAULT), "0" (count)); | 
|  | 137 |  | 
|  | 138 | return res; | 
|  | 139 | } | 
|  | 140 | EXPORT_SYMBOL(strncpy_from_user); | 
|  | 141 |  | 
|  | 142 | /* | 
|  | 143 | * Return the size of a string (including the ending 0) | 
|  | 144 | * | 
|  | 145 | * Return 0 on exception, a value greater than N if too long | 
|  | 146 | */ | 
|  | 147 | long strnlen_user(const char __user *src, long n) | 
|  | 148 | { | 
|  | 149 | char c; | 
|  | 150 | long res; | 
|  | 151 |  | 
|  | 152 | asm volatile ("\n" | 
|  | 153 | "1:	subq.l	#1,%1\n" | 
|  | 154 | "	jmi	3f\n" | 
|  | 155 | "2:	moves.b	(%0)+,%2\n" | 
|  | 156 | "	tst.b	%2\n" | 
|  | 157 | "	jne	1b\n" | 
|  | 158 | "	jra	4f\n" | 
|  | 159 | "\n" | 
|  | 160 | "3:	addq.l	#1,%0\n" | 
|  | 161 | "4:	sub.l	%4,%0\n" | 
|  | 162 | "5:\n" | 
|  | 163 | "	.section .fixup,\"ax\"\n" | 
|  | 164 | "	.even\n" | 
|  | 165 | "20:	sub.l	%0,%0\n" | 
|  | 166 | "	jra	5b\n" | 
|  | 167 | "	.previous\n" | 
|  | 168 | "\n" | 
|  | 169 | "	.section __ex_table,\"a\"\n" | 
|  | 170 | "	.align	4\n" | 
|  | 171 | "	.long	2b,20b\n" | 
|  | 172 | "	.previous\n" | 
|  | 173 | : "=&a" (res), "+d" (n), "=&d" (c) | 
|  | 174 | : "0" (src), "r" (src)); | 
|  | 175 |  | 
|  | 176 | return res; | 
|  | 177 | } | 
|  | 178 | EXPORT_SYMBOL(strnlen_user); | 
|  | 179 |  | 
|  | 180 | /* | 
|  | 181 | * Zero Userspace | 
|  | 182 | */ | 
|  | 183 |  | 
| Geert Uytterhoeven | 3c46bdc | 2007-05-15 01:41:29 -0700 | [diff] [blame] | 184 | unsigned long __clear_user(void __user *to, unsigned long n) | 
| Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 185 | { | 
|  | 186 | unsigned long res; | 
|  | 187 |  | 
|  | 188 | asm volatile ("\n" | 
|  | 189 | "	tst.l	%0\n" | 
|  | 190 | "	jeq	3f\n" | 
|  | 191 | "1:	moves.l	%2,(%1)+\n" | 
|  | 192 | "2:	subq.l	#1,%0\n" | 
|  | 193 | "	jne	1b\n" | 
|  | 194 | "3:	btst	#1,%4\n" | 
|  | 195 | "	jeq	5f\n" | 
|  | 196 | "4:	moves.w	%2,(%1)+\n" | 
|  | 197 | "5:	btst	#0,%4\n" | 
|  | 198 | "	jeq	7f\n" | 
|  | 199 | "6:	moves.b	%2,(%1)\n" | 
|  | 200 | "7:\n" | 
|  | 201 | "	.section .fixup,\"ax\"\n" | 
|  | 202 | "	.even\n" | 
|  | 203 | "10:	lsl.l	#2,%0\n" | 
|  | 204 | "40:	add.l	%4,%0\n" | 
|  | 205 | "	jra	7b\n" | 
|  | 206 | "	.previous\n" | 
|  | 207 | "\n" | 
|  | 208 | "	.section __ex_table,\"a\"\n" | 
|  | 209 | "	.align	4\n" | 
|  | 210 | "	.long	1b,10b\n" | 
|  | 211 | "	.long	2b,10b\n" | 
|  | 212 | "	.long	4b,40b\n" | 
|  | 213 | "	.long	5b,40b\n" | 
|  | 214 | "	.long	6b,40b\n" | 
|  | 215 | "	.long	7b,40b\n" | 
|  | 216 | "	.previous" | 
|  | 217 | : "=d" (res), "+a" (to) | 
|  | 218 | : "r" (0), "0" (n / 4), "d" (n & 3)); | 
|  | 219 |  | 
|  | 220 | return res; | 
|  | 221 | } | 
| Geert Uytterhoeven | 3c46bdc | 2007-05-15 01:41:29 -0700 | [diff] [blame] | 222 | EXPORT_SYMBOL(__clear_user); |