aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/lib/usercopy.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /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.c636
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
16static 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) \
32do { \
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 */
80long
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 */
106long
107strncpy_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) \
121do { \
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 */
152unsigned long
153clear_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 */
172unsigned 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 */
190long 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
223static 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
330static 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 */
429unsigned long
430__copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size);
431unsigned 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) \
437do { \
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) \
473do { \
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
515unsigned 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
537survive:
538 down_read(&current->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(&current->mm->mmap_sem);
544 blk_congestion_wait(WRITE, HZ/50);
545 goto survive;
546 }
547
548 if (retval != 1) {
549 up_read(&current->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(&current->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
574unsigned 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 */
598unsigned long
599copy_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}
607EXPORT_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 */
625unsigned long
626copy_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}
636EXPORT_SYMBOL(copy_from_user);