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" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 18 | "1: "MOVES".l (%1)+,%3\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 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" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 24 | "3: "MOVES".w (%1)+,%3\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 25 | " move.w %3,(%2)+\n" |
| 26 | "4: btst #0,%5\n" |
| 27 | " jeq 6f\n" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 28 | "5: "MOVES".b (%1)+,%3\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 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" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 71 | "2: "MOVES".l %3,(%2)+\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 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" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 77 | "5: "MOVES".w %3,(%2)+\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 78 | "6: btst #0,%5\n" |
| 79 | " jeq 8f\n" |
| 80 | " move.b (%1)+,%3\n" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 81 | "7: "MOVES".b %3,(%2)+\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 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" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 118 | "1: "MOVES".b (%2)+,%4\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 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" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 155 | "2: "MOVES".b (%0)+,%2\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 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" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 191 | "1: "MOVES".l %2,(%1)+\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 192 | "2: subq.l #1,%0\n" |
| 193 | " jne 1b\n" |
| 194 | "3: btst #1,%4\n" |
| 195 | " jeq 5f\n" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 196 | "4: "MOVES".w %2,(%1)+\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 197 | "5: btst #0,%4\n" |
| 198 | " jeq 7f\n" |
Greg Ungerer | e08d703 | 2011-10-14 14:43:30 +1000 | [diff] [blame] | 199 | "6: "MOVES".b %2,(%1)\n" |
Roman Zippel | d94af93 | 2006-06-23 02:05:00 -0700 | [diff] [blame] | 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); |