diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/i386/lib/usercopy.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/i386/lib/usercopy.c')
-rw-r--r-- | arch/i386/lib/usercopy.c | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c new file mode 100644 index 000000000000..51aa2bbb0269 --- /dev/null +++ b/arch/i386/lib/usercopy.c | |||
@@ -0,0 +1,636 @@ | |||
1 | /* | ||
2 | * User address space access functions. | ||
3 | * The non inlined parts of asm-i386/uaccess.h are here. | ||
4 | * | ||
5 | * Copyright 1997 Andi Kleen <ak@muc.de> | ||
6 | * Copyright 1997 Linus Torvalds | ||
7 | */ | ||
8 | #include <linux/config.h> | ||
9 | #include <linux/mm.h> | ||
10 | #include <linux/highmem.h> | ||
11 | #include <linux/blkdev.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <asm/uaccess.h> | ||
14 | #include <asm/mmx.h> | ||
15 | |||
16 | static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n) | ||
17 | { | ||
18 | #ifdef CONFIG_X86_INTEL_USERCOPY | ||
19 | if (n >= 64 && ((a1 ^ a2) & movsl_mask.mask)) | ||
20 | return 0; | ||
21 | #endif | ||
22 | return 1; | ||
23 | } | ||
24 | #define movsl_is_ok(a1,a2,n) \ | ||
25 | __movsl_is_ok((unsigned long)(a1),(unsigned long)(a2),(n)) | ||
26 | |||
27 | /* | ||
28 | * Copy a null terminated string from userspace. | ||
29 | */ | ||
30 | |||
31 | #define __do_strncpy_from_user(dst,src,count,res) \ | ||
32 | do { \ | ||
33 | int __d0, __d1, __d2; \ | ||
34 | might_sleep(); \ | ||
35 | __asm__ __volatile__( \ | ||
36 | " testl %1,%1\n" \ | ||
37 | " jz 2f\n" \ | ||
38 | "0: lodsb\n" \ | ||
39 | " stosb\n" \ | ||
40 | " testb %%al,%%al\n" \ | ||
41 | " jz 1f\n" \ | ||
42 | " decl %1\n" \ | ||
43 | " jnz 0b\n" \ | ||
44 | "1: subl %1,%0\n" \ | ||
45 | "2:\n" \ | ||
46 | ".section .fixup,\"ax\"\n" \ | ||
47 | "3: movl %5,%0\n" \ | ||
48 | " jmp 2b\n" \ | ||
49 | ".previous\n" \ | ||
50 | ".section __ex_table,\"a\"\n" \ | ||
51 | " .align 4\n" \ | ||
52 | " .long 0b,3b\n" \ | ||
53 | ".previous" \ | ||
54 | : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ | ||
55 | "=&D" (__d2) \ | ||
56 | : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ | ||
57 | : "memory"); \ | ||
58 | } while (0) | ||
59 | |||
60 | /** | ||
61 | * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking. | ||
62 | * @dst: Destination address, in kernel space. This buffer must be at | ||
63 | * least @count bytes long. | ||
64 | * @src: Source address, in user space. | ||
65 | * @count: Maximum number of bytes to copy, including the trailing NUL. | ||
66 | * | ||
67 | * Copies a NUL-terminated string from userspace to kernel space. | ||
68 | * Caller must check the specified block with access_ok() before calling | ||
69 | * this function. | ||
70 | * | ||
71 | * On success, returns the length of the string (not including the trailing | ||
72 | * NUL). | ||
73 | * | ||
74 | * If access to userspace fails, returns -EFAULT (some data may have been | ||
75 | * copied). | ||
76 | * | ||
77 | * If @count is smaller than the length of the string, copies @count bytes | ||
78 | * and returns @count. | ||
79 | */ | ||
80 | long | ||
81 | __strncpy_from_user(char *dst, const char __user *src, long count) | ||
82 | { | ||
83 | long res; | ||
84 | __do_strncpy_from_user(dst, src, count, res); | ||
85 | return res; | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * strncpy_from_user: - Copy a NUL terminated string from userspace. | ||
90 | * @dst: Destination address, in kernel space. This buffer must be at | ||
91 | * least @count bytes long. | ||
92 | * @src: Source address, in user space. | ||
93 | * @count: Maximum number of bytes to copy, including the trailing NUL. | ||
94 | * | ||
95 | * Copies a NUL-terminated string from userspace to kernel space. | ||
96 | * | ||
97 | * On success, returns the length of the string (not including the trailing | ||
98 | * NUL). | ||
99 | * | ||
100 | * If access to userspace fails, returns -EFAULT (some data may have been | ||
101 | * copied). | ||
102 | * | ||
103 | * If @count is smaller than the length of the string, copies @count bytes | ||
104 | * and returns @count. | ||
105 | */ | ||
106 | long | ||
107 | strncpy_from_user(char *dst, const char __user *src, long count) | ||
108 | { | ||
109 | long res = -EFAULT; | ||
110 | if (access_ok(VERIFY_READ, src, 1)) | ||
111 | __do_strncpy_from_user(dst, src, count, res); | ||
112 | return res; | ||
113 | } | ||
114 | |||
115 | |||
116 | /* | ||
117 | * Zero Userspace | ||
118 | */ | ||
119 | |||
120 | #define __do_clear_user(addr,size) \ | ||
121 | do { \ | ||
122 | int __d0; \ | ||
123 | might_sleep(); \ | ||
124 | __asm__ __volatile__( \ | ||
125 | "0: rep; stosl\n" \ | ||
126 | " movl %2,%0\n" \ | ||
127 | "1: rep; stosb\n" \ | ||
128 | "2:\n" \ | ||
129 | ".section .fixup,\"ax\"\n" \ | ||
130 | "3: lea 0(%2,%0,4),%0\n" \ | ||
131 | " jmp 2b\n" \ | ||
132 | ".previous\n" \ | ||
133 | ".section __ex_table,\"a\"\n" \ | ||
134 | " .align 4\n" \ | ||
135 | " .long 0b,3b\n" \ | ||
136 | " .long 1b,2b\n" \ | ||
137 | ".previous" \ | ||
138 | : "=&c"(size), "=&D" (__d0) \ | ||
139 | : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \ | ||
140 | } while (0) | ||
141 | |||
142 | /** | ||
143 | * clear_user: - Zero a block of memory in user space. | ||
144 | * @to: Destination address, in user space. | ||
145 | * @n: Number of bytes to zero. | ||
146 | * | ||
147 | * Zero a block of memory in user space. | ||
148 | * | ||
149 | * Returns number of bytes that could not be cleared. | ||
150 | * On success, this will be zero. | ||
151 | */ | ||
152 | unsigned long | ||
153 | clear_user(void __user *to, unsigned long n) | ||
154 | { | ||
155 | might_sleep(); | ||
156 | if (access_ok(VERIFY_WRITE, to, n)) | ||
157 | __do_clear_user(to, n); | ||
158 | return n; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * __clear_user: - Zero a block of memory in user space, with less checking. | ||
163 | * @to: Destination address, in user space. | ||
164 | * @n: Number of bytes to zero. | ||
165 | * | ||
166 | * Zero a block of memory in user space. Caller must check | ||
167 | * the specified block with access_ok() before calling this function. | ||
168 | * | ||
169 | * Returns number of bytes that could not be cleared. | ||
170 | * On success, this will be zero. | ||
171 | */ | ||
172 | unsigned long | ||
173 | __clear_user(void __user *to, unsigned long n) | ||
174 | { | ||
175 | __do_clear_user(to, n); | ||
176 | return n; | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * strlen_user: - Get the size of a string in user space. | ||
181 | * @s: The string to measure. | ||
182 | * @n: The maximum valid length | ||
183 | * | ||
184 | * Get the size of a NUL-terminated string in user space. | ||
185 | * | ||
186 | * Returns the size of the string INCLUDING the terminating NUL. | ||
187 | * On exception, returns 0. | ||
188 | * If the string is too long, returns a value greater than @n. | ||
189 | */ | ||
190 | long strnlen_user(const char __user *s, long n) | ||
191 | { | ||
192 | unsigned long mask = -__addr_ok(s); | ||
193 | unsigned long res, tmp; | ||
194 | |||
195 | might_sleep(); | ||
196 | |||
197 | __asm__ __volatile__( | ||
198 | " testl %0, %0\n" | ||
199 | " jz 3f\n" | ||
200 | " andl %0,%%ecx\n" | ||
201 | "0: repne; scasb\n" | ||
202 | " setne %%al\n" | ||
203 | " subl %%ecx,%0\n" | ||
204 | " addl %0,%%eax\n" | ||
205 | "1:\n" | ||
206 | ".section .fixup,\"ax\"\n" | ||
207 | "2: xorl %%eax,%%eax\n" | ||
208 | " jmp 1b\n" | ||
209 | "3: movb $1,%%al\n" | ||
210 | " jmp 1b\n" | ||
211 | ".previous\n" | ||
212 | ".section __ex_table,\"a\"\n" | ||
213 | " .align 4\n" | ||
214 | " .long 0b,2b\n" | ||
215 | ".previous" | ||
216 | :"=r" (n), "=D" (s), "=a" (res), "=c" (tmp) | ||
217 | :"0" (n), "1" (s), "2" (0), "3" (mask) | ||
218 | :"cc"); | ||
219 | return res & mask; | ||
220 | } | ||
221 | |||
222 | #ifdef CONFIG_X86_INTEL_USERCOPY | ||
223 | static unsigned long | ||
224 | __copy_user_intel(void __user *to, const void *from, unsigned long size) | ||
225 | { | ||
226 | int d0, d1; | ||
227 | __asm__ __volatile__( | ||
228 | " .align 2,0x90\n" | ||
229 | "1: movl 32(%4), %%eax\n" | ||
230 | " cmpl $67, %0\n" | ||
231 | " jbe 3f\n" | ||
232 | "2: movl 64(%4), %%eax\n" | ||
233 | " .align 2,0x90\n" | ||
234 | "3: movl 0(%4), %%eax\n" | ||
235 | "4: movl 4(%4), %%edx\n" | ||
236 | "5: movl %%eax, 0(%3)\n" | ||
237 | "6: movl %%edx, 4(%3)\n" | ||
238 | "7: movl 8(%4), %%eax\n" | ||
239 | "8: movl 12(%4),%%edx\n" | ||
240 | "9: movl %%eax, 8(%3)\n" | ||
241 | "10: movl %%edx, 12(%3)\n" | ||
242 | "11: movl 16(%4), %%eax\n" | ||
243 | "12: movl 20(%4), %%edx\n" | ||
244 | "13: movl %%eax, 16(%3)\n" | ||
245 | "14: movl %%edx, 20(%3)\n" | ||
246 | "15: movl 24(%4), %%eax\n" | ||
247 | "16: movl 28(%4), %%edx\n" | ||
248 | "17: movl %%eax, 24(%3)\n" | ||
249 | "18: movl %%edx, 28(%3)\n" | ||
250 | "19: movl 32(%4), %%eax\n" | ||
251 | "20: movl 36(%4), %%edx\n" | ||
252 | "21: movl %%eax, 32(%3)\n" | ||
253 | "22: movl %%edx, 36(%3)\n" | ||
254 | "23: movl 40(%4), %%eax\n" | ||
255 | "24: movl 44(%4), %%edx\n" | ||
256 | "25: movl %%eax, 40(%3)\n" | ||
257 | "26: movl %%edx, 44(%3)\n" | ||
258 | "27: movl 48(%4), %%eax\n" | ||
259 | "28: movl 52(%4), %%edx\n" | ||
260 | "29: movl %%eax, 48(%3)\n" | ||
261 | "30: movl %%edx, 52(%3)\n" | ||
262 | "31: movl 56(%4), %%eax\n" | ||
263 | "32: movl 60(%4), %%edx\n" | ||
264 | "33: movl %%eax, 56(%3)\n" | ||
265 | "34: movl %%edx, 60(%3)\n" | ||
266 | " addl $-64, %0\n" | ||
267 | " addl $64, %4\n" | ||
268 | " addl $64, %3\n" | ||
269 | " cmpl $63, %0\n" | ||
270 | " ja 1b\n" | ||
271 | "35: movl %0, %%eax\n" | ||
272 | " shrl $2, %0\n" | ||
273 | " andl $3, %%eax\n" | ||
274 | " cld\n" | ||
275 | "99: rep; movsl\n" | ||
276 | "36: movl %%eax, %0\n" | ||
277 | "37: rep; movsb\n" | ||
278 | "100:\n" | ||
279 | ".section .fixup,\"ax\"\n" | ||
280 | "101: lea 0(%%eax,%0,4),%0\n" | ||
281 | " jmp 100b\n" | ||
282 | ".previous\n" | ||
283 | ".section __ex_table,\"a\"\n" | ||
284 | " .align 4\n" | ||
285 | " .long 1b,100b\n" | ||
286 | " .long 2b,100b\n" | ||
287 | " .long 3b,100b\n" | ||
288 | " .long 4b,100b\n" | ||
289 | " .long 5b,100b\n" | ||
290 | " .long 6b,100b\n" | ||
291 | " .long 7b,100b\n" | ||
292 | " .long 8b,100b\n" | ||
293 | " .long 9b,100b\n" | ||
294 | " .long 10b,100b\n" | ||
295 | " .long 11b,100b\n" | ||
296 | " .long 12b,100b\n" | ||
297 | " .long 13b,100b\n" | ||
298 | " .long 14b,100b\n" | ||
299 | " .long 15b,100b\n" | ||
300 | " .long 16b,100b\n" | ||
301 | " .long 17b,100b\n" | ||
302 | " .long 18b,100b\n" | ||
303 | " .long 19b,100b\n" | ||
304 | " .long 20b,100b\n" | ||
305 | " .long 21b,100b\n" | ||
306 | " .long 22b,100b\n" | ||
307 | " .long 23b,100b\n" | ||
308 | " .long 24b,100b\n" | ||
309 | " .long 25b,100b\n" | ||
310 | " .long 26b,100b\n" | ||
311 | " .long 27b,100b\n" | ||
312 | " .long 28b,100b\n" | ||
313 | " .long 29b,100b\n" | ||
314 | " .long 30b,100b\n" | ||
315 | " .long 31b,100b\n" | ||
316 | " .long 32b,100b\n" | ||
317 | " .long 33b,100b\n" | ||
318 | " .long 34b,100b\n" | ||
319 | " .long 35b,100b\n" | ||
320 | " .long 36b,100b\n" | ||
321 | " .long 37b,100b\n" | ||
322 | " .long 99b,101b\n" | ||
323 | ".previous" | ||
324 | : "=&c"(size), "=&D" (d0), "=&S" (d1) | ||
325 | : "1"(to), "2"(from), "0"(size) | ||
326 | : "eax", "edx", "memory"); | ||
327 | return size; | ||
328 | } | ||
329 | |||
330 | static unsigned long | ||
331 | __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size) | ||
332 | { | ||
333 | int d0, d1; | ||
334 | __asm__ __volatile__( | ||
335 | " .align 2,0x90\n" | ||
336 | "0: movl 32(%4), %%eax\n" | ||
337 | " cmpl $67, %0\n" | ||
338 | " jbe 2f\n" | ||
339 | "1: movl 64(%4), %%eax\n" | ||
340 | " .align 2,0x90\n" | ||
341 | "2: movl 0(%4), %%eax\n" | ||
342 | "21: movl 4(%4), %%edx\n" | ||
343 | " movl %%eax, 0(%3)\n" | ||
344 | " movl %%edx, 4(%3)\n" | ||
345 | "3: movl 8(%4), %%eax\n" | ||
346 | "31: movl 12(%4),%%edx\n" | ||
347 | " movl %%eax, 8(%3)\n" | ||
348 | " movl %%edx, 12(%3)\n" | ||
349 | "4: movl 16(%4), %%eax\n" | ||
350 | "41: movl 20(%4), %%edx\n" | ||
351 | " movl %%eax, 16(%3)\n" | ||
352 | " movl %%edx, 20(%3)\n" | ||
353 | "10: movl 24(%4), %%eax\n" | ||
354 | "51: movl 28(%4), %%edx\n" | ||
355 | " movl %%eax, 24(%3)\n" | ||
356 | " movl %%edx, 28(%3)\n" | ||
357 | "11: movl 32(%4), %%eax\n" | ||
358 | "61: movl 36(%4), %%edx\n" | ||
359 | " movl %%eax, 32(%3)\n" | ||
360 | " movl %%edx, 36(%3)\n" | ||
361 | "12: movl 40(%4), %%eax\n" | ||
362 | "71: movl 44(%4), %%edx\n" | ||
363 | " movl %%eax, 40(%3)\n" | ||
364 | " movl %%edx, 44(%3)\n" | ||
365 | "13: movl 48(%4), %%eax\n" | ||
366 | "81: movl 52(%4), %%edx\n" | ||
367 | " movl %%eax, 48(%3)\n" | ||
368 | " movl %%edx, 52(%3)\n" | ||
369 | "14: movl 56(%4), %%eax\n" | ||
370 | "91: movl 60(%4), %%edx\n" | ||
371 | " movl %%eax, 56(%3)\n" | ||
372 | " movl %%edx, 60(%3)\n" | ||
373 | " addl $-64, %0\n" | ||
374 | " addl $64, %4\n" | ||
375 | " addl $64, %3\n" | ||
376 | " cmpl $63, %0\n" | ||
377 | " ja 0b\n" | ||
378 | "5: movl %0, %%eax\n" | ||
379 | " shrl $2, %0\n" | ||
380 | " andl $3, %%eax\n" | ||
381 | " cld\n" | ||
382 | "6: rep; movsl\n" | ||
383 | " movl %%eax,%0\n" | ||
384 | "7: rep; movsb\n" | ||
385 | "8:\n" | ||
386 | ".section .fixup,\"ax\"\n" | ||
387 | "9: lea 0(%%eax,%0,4),%0\n" | ||
388 | "16: pushl %0\n" | ||
389 | " pushl %%eax\n" | ||
390 | " xorl %%eax,%%eax\n" | ||
391 | " rep; stosb\n" | ||
392 | " popl %%eax\n" | ||
393 | " popl %0\n" | ||
394 | " jmp 8b\n" | ||
395 | ".previous\n" | ||
396 | ".section __ex_table,\"a\"\n" | ||
397 | " .align 4\n" | ||
398 | " .long 0b,16b\n" | ||
399 | " .long 1b,16b\n" | ||
400 | " .long 2b,16b\n" | ||
401 | " .long 21b,16b\n" | ||
402 | " .long 3b,16b\n" | ||
403 | " .long 31b,16b\n" | ||
404 | " .long 4b,16b\n" | ||
405 | " .long 41b,16b\n" | ||
406 | " .long 10b,16b\n" | ||
407 | " .long 51b,16b\n" | ||
408 | " .long 11b,16b\n" | ||
409 | " .long 61b,16b\n" | ||
410 | " .long 12b,16b\n" | ||
411 | " .long 71b,16b\n" | ||
412 | " .long 13b,16b\n" | ||
413 | " .long 81b,16b\n" | ||
414 | " .long 14b,16b\n" | ||
415 | " .long 91b,16b\n" | ||
416 | " .long 6b,9b\n" | ||
417 | " .long 7b,16b\n" | ||
418 | ".previous" | ||
419 | : "=&c"(size), "=&D" (d0), "=&S" (d1) | ||
420 | : "1"(to), "2"(from), "0"(size) | ||
421 | : "eax", "edx", "memory"); | ||
422 | return size; | ||
423 | } | ||
424 | #else | ||
425 | /* | ||
426 | * Leave these declared but undefined. They should not be any references to | ||
427 | * them | ||
428 | */ | ||
429 | unsigned long | ||
430 | __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size); | ||
431 | unsigned long | ||
432 | __copy_user_intel(void __user *to, const void *from, unsigned long size); | ||
433 | #endif /* CONFIG_X86_INTEL_USERCOPY */ | ||
434 | |||
435 | /* Generic arbitrary sized copy. */ | ||
436 | #define __copy_user(to,from,size) \ | ||
437 | do { \ | ||
438 | int __d0, __d1, __d2; \ | ||
439 | __asm__ __volatile__( \ | ||
440 | " cmp $7,%0\n" \ | ||
441 | " jbe 1f\n" \ | ||
442 | " movl %1,%0\n" \ | ||
443 | " negl %0\n" \ | ||
444 | " andl $7,%0\n" \ | ||
445 | " subl %0,%3\n" \ | ||
446 | "4: rep; movsb\n" \ | ||
447 | " movl %3,%0\n" \ | ||
448 | " shrl $2,%0\n" \ | ||
449 | " andl $3,%3\n" \ | ||
450 | " .align 2,0x90\n" \ | ||
451 | "0: rep; movsl\n" \ | ||
452 | " movl %3,%0\n" \ | ||
453 | "1: rep; movsb\n" \ | ||
454 | "2:\n" \ | ||
455 | ".section .fixup,\"ax\"\n" \ | ||
456 | "5: addl %3,%0\n" \ | ||
457 | " jmp 2b\n" \ | ||
458 | "3: lea 0(%3,%0,4),%0\n" \ | ||
459 | " jmp 2b\n" \ | ||
460 | ".previous\n" \ | ||
461 | ".section __ex_table,\"a\"\n" \ | ||
462 | " .align 4\n" \ | ||
463 | " .long 4b,5b\n" \ | ||
464 | " .long 0b,3b\n" \ | ||
465 | " .long 1b,2b\n" \ | ||
466 | ".previous" \ | ||
467 | : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \ | ||
468 | : "3"(size), "0"(size), "1"(to), "2"(from) \ | ||
469 | : "memory"); \ | ||
470 | } while (0) | ||
471 | |||
472 | #define __copy_user_zeroing(to,from,size) \ | ||
473 | do { \ | ||
474 | int __d0, __d1, __d2; \ | ||
475 | __asm__ __volatile__( \ | ||
476 | " cmp $7,%0\n" \ | ||
477 | " jbe 1f\n" \ | ||
478 | " movl %1,%0\n" \ | ||
479 | " negl %0\n" \ | ||
480 | " andl $7,%0\n" \ | ||
481 | " subl %0,%3\n" \ | ||
482 | "4: rep; movsb\n" \ | ||
483 | " movl %3,%0\n" \ | ||
484 | " shrl $2,%0\n" \ | ||
485 | " andl $3,%3\n" \ | ||
486 | " .align 2,0x90\n" \ | ||
487 | "0: rep; movsl\n" \ | ||
488 | " movl %3,%0\n" \ | ||
489 | "1: rep; movsb\n" \ | ||
490 | "2:\n" \ | ||
491 | ".section .fixup,\"ax\"\n" \ | ||
492 | "5: addl %3,%0\n" \ | ||
493 | " jmp 6f\n" \ | ||
494 | "3: lea 0(%3,%0,4),%0\n" \ | ||
495 | "6: pushl %0\n" \ | ||
496 | " pushl %%eax\n" \ | ||
497 | " xorl %%eax,%%eax\n" \ | ||
498 | " rep; stosb\n" \ | ||
499 | " popl %%eax\n" \ | ||
500 | " popl %0\n" \ | ||
501 | " jmp 2b\n" \ | ||
502 | ".previous\n" \ | ||
503 | ".section __ex_table,\"a\"\n" \ | ||
504 | " .align 4\n" \ | ||
505 | " .long 4b,5b\n" \ | ||
506 | " .long 0b,3b\n" \ | ||
507 | " .long 1b,6b\n" \ | ||
508 | ".previous" \ | ||
509 | : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \ | ||
510 | : "3"(size), "0"(size), "1"(to), "2"(from) \ | ||
511 | : "memory"); \ | ||
512 | } while (0) | ||
513 | |||
514 | |||
515 | unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n) | ||
516 | { | ||
517 | BUG_ON((long) n < 0); | ||
518 | #ifndef CONFIG_X86_WP_WORKS_OK | ||
519 | if (unlikely(boot_cpu_data.wp_works_ok == 0) && | ||
520 | ((unsigned long )to) < TASK_SIZE) { | ||
521 | /* | ||
522 | * CPU does not honor the WP bit when writing | ||
523 | * from supervisory mode, and due to preemption or SMP, | ||
524 | * the page tables can change at any time. | ||
525 | * Do it manually. Manfred <manfred@colorfullife.com> | ||
526 | */ | ||
527 | while (n) { | ||
528 | unsigned long offset = ((unsigned long)to)%PAGE_SIZE; | ||
529 | unsigned long len = PAGE_SIZE - offset; | ||
530 | int retval; | ||
531 | struct page *pg; | ||
532 | void *maddr; | ||
533 | |||
534 | if (len > n) | ||
535 | len = n; | ||
536 | |||
537 | survive: | ||
538 | down_read(¤t->mm->mmap_sem); | ||
539 | retval = get_user_pages(current, current->mm, | ||
540 | (unsigned long )to, 1, 1, 0, &pg, NULL); | ||
541 | |||
542 | if (retval == -ENOMEM && current->pid == 1) { | ||
543 | up_read(¤t->mm->mmap_sem); | ||
544 | blk_congestion_wait(WRITE, HZ/50); | ||
545 | goto survive; | ||
546 | } | ||
547 | |||
548 | if (retval != 1) { | ||
549 | up_read(¤t->mm->mmap_sem); | ||
550 | break; | ||
551 | } | ||
552 | |||
553 | maddr = kmap_atomic(pg, KM_USER0); | ||
554 | memcpy(maddr + offset, from, len); | ||
555 | kunmap_atomic(maddr, KM_USER0); | ||
556 | set_page_dirty_lock(pg); | ||
557 | put_page(pg); | ||
558 | up_read(¤t->mm->mmap_sem); | ||
559 | |||
560 | from += len; | ||
561 | to += len; | ||
562 | n -= len; | ||
563 | } | ||
564 | return n; | ||
565 | } | ||
566 | #endif | ||
567 | if (movsl_is_ok(to, from, n)) | ||
568 | __copy_user(to, from, n); | ||
569 | else | ||
570 | n = __copy_user_intel(to, from, n); | ||
571 | return n; | ||
572 | } | ||
573 | |||
574 | unsigned long | ||
575 | __copy_from_user_ll(void *to, const void __user *from, unsigned long n) | ||
576 | { | ||
577 | BUG_ON((long)n < 0); | ||
578 | if (movsl_is_ok(to, from, n)) | ||
579 | __copy_user_zeroing(to, from, n); | ||
580 | else | ||
581 | n = __copy_user_zeroing_intel(to, from, n); | ||
582 | return n; | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * copy_to_user: - Copy a block of data into user space. | ||
587 | * @to: Destination address, in user space. | ||
588 | * @from: Source address, in kernel space. | ||
589 | * @n: Number of bytes to copy. | ||
590 | * | ||
591 | * Context: User context only. This function may sleep. | ||
592 | * | ||
593 | * Copy data from kernel space to user space. | ||
594 | * | ||
595 | * Returns number of bytes that could not be copied. | ||
596 | * On success, this will be zero. | ||
597 | */ | ||
598 | unsigned long | ||
599 | copy_to_user(void __user *to, const void *from, unsigned long n) | ||
600 | { | ||
601 | might_sleep(); | ||
602 | BUG_ON((long) n < 0); | ||
603 | if (access_ok(VERIFY_WRITE, to, n)) | ||
604 | n = __copy_to_user(to, from, n); | ||
605 | return n; | ||
606 | } | ||
607 | EXPORT_SYMBOL(copy_to_user); | ||
608 | |||
609 | /** | ||
610 | * copy_from_user: - Copy a block of data from user space. | ||
611 | * @to: Destination address, in kernel space. | ||
612 | * @from: Source address, in user space. | ||
613 | * @n: Number of bytes to copy. | ||
614 | * | ||
615 | * Context: User context only. This function may sleep. | ||
616 | * | ||
617 | * Copy data from user space to kernel space. | ||
618 | * | ||
619 | * Returns number of bytes that could not be copied. | ||
620 | * On success, this will be zero. | ||
621 | * | ||
622 | * If some data could not be copied, this function will pad the copied | ||
623 | * data to the requested size using zero bytes. | ||
624 | */ | ||
625 | unsigned long | ||
626 | copy_from_user(void *to, const void __user *from, unsigned long n) | ||
627 | { | ||
628 | might_sleep(); | ||
629 | BUG_ON((long) n < 0); | ||
630 | if (access_ok(VERIFY_READ, from, n)) | ||
631 | n = __copy_from_user(to, from, n); | ||
632 | else | ||
633 | memset(to, 0, n); | ||
634 | return n; | ||
635 | } | ||
636 | EXPORT_SYMBOL(copy_from_user); | ||