1 /*
2 * User address space access functions.
3 *
4 * Copyright 1997 Andi Kleen <ak@muc.de>
5 * Copyright 1997 Linus Torvalds
6 * Copyright 2002 Andi Kleen <ak@suse.de>
7 */
8 #include <asm/uaccess.h>
9
10 /*
11 * Copy a null terminated string from userspace.
12 */
13
14 #define __do_strncpy_from_user(dst,src,count,res) \
15 do { \
16 long __d0, __d1, __d2; \
17 __asm__ __volatile__( \
18 " testq %1,%1\n" \
19 " jz 2f\n" \
20 "0: lodsb\n" \
21 " stosb\n" \
22 " testb %%al,%%al\n" \
23 " jz 1f\n" \
24 " decq %1\n" \
25 " jnz 0b\n" \
26 "1: subq %1,%0\n" \
27 "2:\n" \
28 ".section .fixup,\"ax\"\n" \
29 "3: movq %5,%0\n" \
30 " jmp 2b\n" \
31 ".previous\n" \
32 ".section __ex_table,\"a\"\n" \
33 " .align 8\n" \
34 " .quad 0b,3b\n" \
35 ".previous" \
36 : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
37 "=&D" (__d2) \
38 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
39 : "memory"); \
40 } while (0)
41
42 long
__strncpy_from_user(char * dst,const char * src,long count)43 __strncpy_from_user(char *dst, const char *src, long count)
44 {
45 long res;
46 __do_strncpy_from_user(dst, src, count, res);
47 return res;
48 }
49
50 long
strncpy_from_user(char * dst,const char * src,long count)51 strncpy_from_user(char *dst, const char *src, long count)
52 {
53 long res = -EFAULT;
54 if (access_ok(VERIFY_READ, src, 1))
55 __do_strncpy_from_user(dst, src, count, res);
56 return res;
57 }
58
59 /*
60 * Zero Userspace
61 */
62
__clear_user(void * addr,unsigned long size)63 unsigned long __clear_user(void *addr, unsigned long size)
64 {
65 long __d0;
66 /* no memory constraint because it doesn't change any memory gcc knows
67 about */
68 asm volatile(
69 " testq %[size8],%[size8]\n"
70 " jz 4f\n"
71 "0: movq %[zero],(%[dst])\n"
72 " addq %[eight],%[dst]\n"
73 " decl %%ecx ; jnz 0b\n"
74 "4: movq %[size1],%%rcx\n"
75 " testl %%ecx,%%ecx\n"
76 " jz 2f\n"
77 "1: movb %b[zero],(%[dst])\n"
78 " incq %[dst]\n"
79 " decl %%ecx ; jnz 1b\n"
80 "2:\n"
81 ".section .fixup,\"ax\"\n"
82 "3: lea 0(%[size1],%[size8],8),%[size8]\n"
83 " jmp 2b\n"
84 ".previous\n"
85 ".section __ex_table,\"a\"\n"
86 " .align 8\n"
87 " .quad 0b,3b\n"
88 " .quad 1b,2b\n"
89 ".previous"
90 : [size8] "=c"(size), [dst] "=&D" (__d0)
91 : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
92 [zero] "r" (0UL), [eight] "r" (8UL));
93 return size;
94 }
95
96
clear_user(void * to,unsigned long n)97 unsigned long clear_user(void *to, unsigned long n)
98 {
99 if (access_ok(VERIFY_WRITE, to, n))
100 return __clear_user(to, n);
101 return n;
102 }
103
104 /*
105 * Return the size of a string (including the ending 0)
106 *
107 * Return 0 on exception, a value greater than N if too long
108 */
109
strnlen_user(const char * s,long n)110 long strnlen_user(const char *s, long n)
111 {
112 unsigned long res = 0;
113 char c;
114
115 if (!access_ok(VERIFY_READ, s, n))
116 return 0;
117
118 while (1) {
119 if (get_user(c, s))
120 return 0;
121 if (!c)
122 return res+1;
123 if (res>n)
124 return n+1;
125 res++;
126 s++;
127 }
128 }
129
copy_in_user(void * to,const void * from,unsigned len)130 unsigned long copy_in_user(void *to, const void *from, unsigned len)
131 {
132 if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
133 return copy_user_generic(to, from, len);
134 }
135 return len;
136 }
137