usercopy.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:3k
- /*
- * User address space access functions.
- *
- * Copyright 1997 Andi Kleen <ak@muc.de>
- * Copyright 1997 Linus Torvalds
- * Copyright 2002 Andi Kleen <ak@suse.de>
- */
- #include <asm/uaccess.h>
- /*
- * Copy a null terminated string from userspace.
- */
- #define __do_strncpy_from_user(dst,src,count,res)
- do {
- long __d0, __d1, __d2;
- __asm__ __volatile__(
- " testq %1,%1n"
- " jz 2fn"
- "0: lodsbn"
- " stosbn"
- " testb %%al,%%aln"
- " jz 1fn"
- " decq %1n"
- " jnz 0bn"
- "1: subq %1,%0n"
- "2:n"
- ".section .fixup,"ax"n"
- "3: movq %5,%0n"
- " jmp 2bn"
- ".previousn"
- ".section __ex_table,"a"n"
- " .align 4n"
- " .quad 0b,3bn"
- ".previous"
- : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),
- "=&D" (__d2)
- : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst)
- : "memory");
- } while (0)
- long
- __strncpy_from_user(char *dst, const char *src, long count)
- {
- long res;
- __do_strncpy_from_user(dst, src, count, res);
- return res;
- }
- long
- strncpy_from_user(char *dst, const char *src, long count)
- {
- long res = -EFAULT;
- if (access_ok(VERIFY_READ, src, 1))
- __do_strncpy_from_user(dst, src, count, res);
- return res;
- }
- /*
- * Zero Userspace
- */
- unsigned long __clear_user(void *addr, unsigned long size)
- {
- long __d0;
- /* no memory constraint because it doesn't change any memory gcc knows
- about */
- asm volatile(
- " testq %[size8],%[size8]n"
- " jz 4fn"
- "0: movnti %[zero],(%[dst])n"
- " addq %[eight],%[dst]n"
- " decl %%ecx ; jnz 0bn"
- "4: movq %[size1],%%rcxn"
- " testl %%ecx,%%ecxn"
- " jz 2fn"
- "1: movb %b[zero],(%[dst])n"
- " incq %[dst]n"
- " decl %%ecx ; jnz 1bn"
- "2: sfencen"
- ".section .fixup,"ax"n"
- "3: lea 0(%[size1],%[size8],8),%[size8]n"
- " jmp 2bn"
- ".previousn"
- ".section __ex_table,"a"n"
- " .align 8n"
- " .quad 0b,3bn"
- " .quad 1b,2bn"
- ".previous"
- : [size8] "=c"(size), [dst] "=&D" (__d0)
- : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst] "(addr),
- [zero] "r" (0UL), [eight] "r" (8UL));
- return size;
- }
- unsigned long clear_user(void *to, unsigned long n)
- {
- if (access_ok(VERIFY_WRITE, to, n))
- return __clear_user(to, n);
- return n;
- }
- /*
- * 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 *s, long n)
- {
- unsigned long res = 0;
- char c;
- if (!access_ok(VERIFY_READ, s, n))
- return 0;
- while (1) {
- if (get_user(c, s))
- return 0;
- if (!c)
- return res+1;
- if (res>n)
- return n+1;
- res++;
- s++;
- }
- }